using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using RevitEstimate.Models;

namespace RevitEstimate.Calculators
{
    public class Item54Calculator : IItemCalculator
    {
        private ProjectLevels _levels;

        public Item54Calculator(ProjectLevels levels = null)
        {
            _levels = levels ?? new ProjectLevels();
        }

        public List<EstimateRowModel> Calculate(List<Element> collector, out double totalQty)
        {
            totalQty = 0.0;
            var rows = new List<EstimateRowModel>();

            var stairs = collector
                .Where(e => e.Category != null && e.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Stairs)
                .ToList();

            if (stairs.Count == 0)
            {
                rows.Add(new EstimateRowModel { SNo = "", ItemOfWork = "   -> [No Stairs found]", Qty = "0.00", Unit = "Cum" });
                return rows;
            }

            foreach (var stair in stairs)
            {
                string stairName = stair.Name;
                ElementId stairId = stair.Id;

                int actualRisers = GetParameterInt(stair, "Actual Risers") > 0 ? GetParameterInt(stair, "Actual Risers") : 15;
                int actualTreads = GetParameterInt(stair, "Actual Treads") > 0 ? GetParameterInt(stair, "Actual Treads") : 14;
                double riserHeight = GetParameterDouble(stair, "Actual Riser Height") > 0 ? GetParameterDouble(stair, "Actual Riser Height") : 0.15;
                double treadDepth = GetParameterDouble(stair, "Actual Tread Depth") > 0 ? GetParameterDouble(stair, "Actual Tread Depth") : 0.25;
                double stairWidth = GetParameterDouble(stair, "Width") > 0 ? GetParameterDouble(stair, "Width") : 1.20;

                double totalGoing = actualTreads * treadDepth;
                double totalRise = actualRisers * riserHeight;
                double slantLength = Math.Sqrt((totalGoing * totalGoing) + (totalRise * totalRise));
                double waistThickness = 0.15;

                // 1. Waist Slab
                double qtyWaistSlab = slantLength * stairWidth * waistThickness;
                totalQty += qtyWaistSlab;

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = $"   -> Waist Slab (Slant Slab 15cm) for Stair: {stairName} [ID: {stairId}]",
                    NosOfFlats = "1",
                    NosOfInstance = "1",
                    Length = slantLength.ToString("F2"),
                    Width = stairWidth.ToString("F2"),
                    HeightDepth = waistThickness.ToString("F2"),
                    Qty = qtyWaistSlab.ToString("F2"),
                    Unit = "Cum",
                    Remarks = $"Waist slab volume (Slant L={slantLength:F2}m x W={stairWidth:F2}m x Thk={waistThickness}m)."
                });

                // 2. Steps
                double singleStepVol = 0.5 * riserHeight * treadDepth * stairWidth;
                double qtySteps = actualTreads * singleStepVol;
                totalQty += qtySteps;

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = $"   -> Steps (Treads & Risers block) for Stair: {stairName} [ID: {stairId}]",
                    NosOfFlats = "1",
                    NosOfInstance = actualTreads.ToString(),
                    Length = treadDepth.ToString("F2"),
                    Width = stairWidth.ToString("F2"),
                    HeightDepth = riserHeight.ToString("F2"),
                    Qty = qtySteps.ToString("F2"),
                    Unit = "Cum",
                    Remarks = $"Steps concrete volume ({actualTreads} nos steps x 0.5 x R x T x W)."
                });

                // 3. Landings
                double landingArea = GetLandingArea(stair);
                double landingThickness = 0.15;
                double qtyLanding = landingArea * landingThickness;
                totalQty += qtyLanding;

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = $"   -> Landing Slab (15cm thick) for Stair: {stairName} [ID: {stairId}]",
                    NosOfFlats = "1",
                    NosOfInstance = "1",
                    Length = landingArea.ToString("F2"),
                    Width = "",
                    HeightDepth = landingThickness.ToString("F2"),
                    Qty = qtyLanding.ToString("F2"),
                    Unit = "Cum",
                    Remarks = $"Landing slab concrete volume (Area={landingArea:F2} Sqm x Thk={landingThickness}m)."
                });
            }

            return rows;
        }

        private int GetParameterInt(Element elem, string paramName)
        {
            Parameter param = elem.LookupParameter(paramName);
            if (param != null && param.HasValue) return param.AsInteger();
            return 0;
        }

        private double GetParameterDouble(Element elem, string paramName)
        {
            Parameter param = elem.LookupParameter(paramName);
            if (param != null && param.HasValue)
            {
                return UnitUtils.ConvertFromInternalUnits(param.AsDouble(), UnitTypeId.Meters);
            }
            return 0.0;
        }

        private double GetLandingArea(Element stair)
        {
            try
            {
                BoundingBoxXYZ box = stair.get_BoundingBox(null);
                if (box != null)
                {
                    double width = UnitUtils.ConvertFromInternalUnits(box.Max.X - box.Min.X, UnitTypeId.Meters);
                    double length = UnitUtils.ConvertFromInternalUnits(box.Max.Y - box.Min.Y, UnitTypeId.Meters);
                    if (width > 0 && length > 0)
                    {
                        return Math.Round(width * length * 0.3, 2);
                    }
                }
            }
            catch { }
            return 1.5;
        }
    }
}