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

namespace RevitEstimate.Calculators
{
    public class Item44Calculator : IItemCalculator
    {
        private ProjectLevels _levels;
        public Item44Calculator(ProjectLevels levels = null) => _levels = levels ?? new ProjectLevels();

        private class FloorLevelInfo { public string Name { get; set; } public double BottomZ { get; set; } public double TopZ { get; set; } }

        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;

            var activeFloors = new List<FloorLevelInfo>();
            activeFloors.Add(new FloorLevelInfo { Name = "GF", BottomZ = _levels.TopOfPlinth, TopZ = _levels.SlabTop });
            double currentTop = _levels.SlabTop;
            if (_levels.FirstFloorSlabTop != -8888 && _levels.FirstFloorSlabTop != 0) { activeFloors.Add(new FloorLevelInfo { Name = "FF", BottomZ = currentTop, TopZ = _levels.FirstFloorSlabTop }); currentTop = _levels.FirstFloorSlabTop; }
            if (_levels.SecondFloorSlabTop != -8888 && _levels.SecondFloorSlabTop != 0) { activeFloors.Add(new FloorLevelInfo { Name = "SF", BottomZ = currentTop, TopZ = _levels.SecondFloorSlabTop }); currentTop = _levels.SecondFloorSlabTop; }
            if (_levels.ThirdFloorSlabTop != -8888 && _levels.ThirdFloorSlabTop != 0) { activeFloors.Add(new FloorLevelInfo { Name = "TF", BottomZ = currentTop, TopZ = _levels.ThirdFloorSlabTop }); currentTop = _levels.ThirdFloorSlabTop; }
            if (_levels.TerraceRoofTop != -8888 && _levels.TerraceRoofTop != 0) { activeFloors.Add(new FloorLevelInfo { Name = "Terrace", BottomZ = currentTop, TopZ = _levels.TerraceRoofTop }); }

            // ==========================================
            // PART 1: WALL PUTTY (Picking from Item 22 & Item 23 Plaster net areas)
            // ==========================================
            double outerPlasterQty = 0.0;
            double innerPlasterQty = 0.0;

            var item22Calc = new Item22Calculator(_levels);
            var item22Rows = item22Calc.Calculate(collector, out outerPlasterQty);

            var item23Calc = new Item23Calculator(_levels);
            var item23Rows = item23Calc.Calculate(collector, out innerPlasterQty);

            double totalWallPuttyQty = outerPlasterQty + innerPlasterQty;
            totalQty += totalWallPuttyQty;

            rows.Add(new EstimateRowModel
            {
                SNo = "",
                ItemOfWork = "   -> Wall Putty (Picked from Outer & Inner Plaster net areas)",
                NosOfFlats = "1",
                NosOfInstance = "1",
                Length = totalWallPuttyQty.ToString("F2"),
                Width = "",
                HeightDepth = "",
                Qty = totalWallPuttyQty.ToString("F2"),
                Unit = "Sqm",
                Remarks = $"Total Wall Putty = Outer Plaster ({outerPlasterQty:F2}) + Inner Plaster ({innerPlasterQty:F2})."
            });

            // ==========================================
            // PART 2: CEILING PUTTY (Include Stilt, Exclude Open Area)
            // ==========================================
            var rooms = collector.Where(e => e is Room).Cast<Room>().ToList();
            if (rooms.Count == 0) rooms = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Rooms).Cast<Room>().ToList();

            foreach (var room in rooms)
            {
                string roomName = room.Name ?? "";
                string roomLower = roomName.ToLower();

                // Exclude only "open area", "courtyard", "parking" (Stilt is included as requested)
                bool isExcluded = roomLower.Contains("open") || roomLower.Contains("courtyard") || roomLower.Contains("parking");
                if (isExcluded) continue;

                double roomZ = room.Level != null ? UnitUtils.ConvertFromInternalUnits(room.Level.Elevation, UnitTypeId.Meters) : 0;
                var floor = activeFloors.FirstOrDefault(f => roomZ >= (f.BottomZ - 0.5) && roomZ <= (f.TopZ + 0.5)) ?? activeFloors.First();

                double area = UnitUtils.ConvertFromInternalUnits(room.Area, UnitTypeId.SquareMeters);
                if (area <= 0) continue;

                totalQty += area;

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = $"   -> Ceiling Putty in {roomName} ({floor.Name}) [ID: {room.Id}]",
                    NosOfFlats = "1",
                    NosOfInstance = "1",
                    Length = area.ToString("F2"),
                    Width = "",
                    HeightDepth = "",
                    Qty = area.ToString("F2"),
                    Unit = "Sqm",
                    Remarks = $"Ceiling putty area from room tag '{roomName}' inner L & B."
                });
            }

            return rows;
        }
    }
}