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

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

        public Item21Calculator(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>();

            Document doc = collector.FirstOrDefault()?.Document;
            if (doc == null) return rows;

            // ==========================================
            // FILTER REBARS ABOVE PLINTH LEVEL
            // ==========================================
            double topPlinth = _levels.TopOfPlinth;

            // Collect all Rebar elements
            var rebars = collector.Where(e => e.Category != null && e.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Rebar).ToList();

            // Filter rebars that are in the superstructure (above Top of Plinth)
            var superstructureRebars = rebars.Where(r => GetElementZCoordinate(r) > topPlinth).ToList();

            if (superstructureRebars.Count > 0)
            {
                foreach (var rebar in superstructureRebars)
                {
                    double length = GetRebarLength(rebar);
                    double diameter = GetRebarDiameter(rebar); // in mm

                    // Standard weight calculation formula: Weight per meter = D^2 / 162
                    double weightPerMeter = (diameter * diameter) / 162.0;
                    double qty = length * weightPerMeter; // Total Kg for this instance

                    totalQty += qty;

                    rows.Add(new EstimateRowModel
                    {
                        SNo = "",
                        ItemOfWork = $"   -> Rebar Fe-500D ({diameter}mm dia) [ID: {rebar.Id}]",
                        NosOfFlats = "1",
                        NosOfInstance = "1",
                        Length = length.ToString("F2"),
                        Width = "-",
                        HeightDepth = "-",
                        Qty = qty.ToString("F2"),
                        Unit = "Kg",
                        Remarks = "As per bar bending schedule" // <-- Aapki requirement ke anusaar
                    });
                }
            }
            else
            {
                // Agar model me rebars modelled nahi hain, tab bhi row aayegi with remark
                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = "   -> Steel reinforcement for R.C.C. work (Superstructure)",
                    NosOfFlats = "-",
                    NosOfInstance = "-",
                    Length = "-",
                    Width = "-",
                    HeightDepth = "-",
                    Qty = "0.00",
                    Unit = "Kg",
                    Remarks = "As per bar bending schedule" // <-- Aapki requirement ke anusaar
                });
            }

            return rows;
        }

        private double GetRebarLength(Element rebar)
        {
            Parameter lenParam = rebar.LookupParameter("Total Bar Length") ?? rebar.LookupParameter("Bar Length");
            if (lenParam != null && lenParam.HasValue)
            {
                return UnitUtils.ConvertFromInternalUnits(lenParam.AsDouble(), UnitTypeId.Meters);
            }
            return 0.0;
        }

        private double GetRebarDiameter(Element rebar)
        {
            ElementId typeId = rebar.GetTypeId();
            if (typeId != ElementId.InvalidElementId && rebar.Document != null)
            {
                Element typeElem = rebar.Document.GetElement(typeId);
                if (typeElem != null)
                {
                    Parameter diaParam = typeElem.LookupParameter("Bar Diameter") ?? typeElem.LookupParameter("Diameter");
                    if (diaParam != null && diaParam.HasValue)
                    {
                        return UnitUtils.ConvertFromInternalUnits(diaParam.AsDouble(), UnitTypeId.Millimeters);
                    }
                }
            }
            return 10.0; // Default fallback to 10mm
        }

        private double GetElementZCoordinate(Element elem)
        {
            BoundingBoxXYZ box = elem.get_BoundingBox(null);
            if (box != null) return UnitUtils.ConvertFromInternalUnits((box.Min.Z + box.Max.Z) / 2.0, UnitTypeId.Meters);
            return 0.0;
        }
    }
}