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 Item02Calculator : IItemCalculator
    {
        private ProjectLevels _levels;

        public Item02Calculator(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)
            {
                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = "   -> [Document reference missing for rooms]",
                    NosOfFlats = "-",
                    NosOfInstance = "0",
                    Length = "-",
                    Width = "-",
                    HeightDepth = "-",
                    Qty = "0.00",
                    Unit = "-",
                    Remarks = "Error accessing document."
                });
                return rows;
            }

            // 1. Collect all Rooms from the model
            var rooms = new FilteredElementCollector(doc)
                .OfCategory(BuiltInCategory.OST_Rooms)
                .WhereElementIsNotElementType()
                .Cast<Room>()
                .Where(r => r.Area > 0)
                .ToList();

            // Check if room tags / rooms exist - Warning prompt
            if (rooms.Count == 0)
            {
                System.Windows.MessageBox.Show(
                    "Warning: Room tags / Rooms are not found in the Revit model! Please tag the rooms before generating Item 2 estimate.",
                    "Room Tag Missing",
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Warning);

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = "   -> [Warning: No rooms/room tags found in model for earth filling]",
                    NosOfFlats = "-",
                    NosOfInstance = "0",
                    Length = "-",
                    Width = "-",
                    HeightDepth = "-",
                    Qty = "0.00",
                    Unit = "-",
                    Remarks = "Rooms must be tagged for Item 2 calculation."
                });
                return rows;
            }

            // Depth = Top of Plinth - GroundLevel (or using available level properties safely)
            double depthPL = Math.Abs(_levels.TopOfPlinth - _levels.GroundLevel);
            if (depthPL <= 0)
            {
                depthPL = 0.6; // Fallback depth
            }

            foreach (var room in rooms)
            {
                string roomName = room.Name ?? "Unnamed Room";
                string roomNumber = room.Number ?? "";
                string displayRoomName = string.IsNullOrEmpty(roomNumber) ? roomName : $"{roomName} ({roomNumber})";

                GetRoomInternalDimensions(room, out double roomLength, out double roomWidth);

                double roomQty = roomLength * roomWidth * depthPL;
                totalQty += roomQty;

                string remarkText = $"Earth filling in room '{displayRoomName}', Length ({roomLength:F2}m), Width ({roomWidth:F2}m), Depth (Top of Plinth - Ground Level: {depthPL:F2}m).";

                rows.Add(new EstimateRowModel
                {
                    SNo = "",
                    ItemOfWork = $"   -> Filling in Room: {displayRoomName}",
                    NosOfFlats = "1",
                    NosOfInstance = "1",
                    Length = roomLength.ToString("F2"),
                    Width = roomWidth.ToString("F2"),
                    HeightDepth = depthPL.ToString("F2"),
                    Qty = roomQty.ToString("F2"),
                    Unit = "Cum",
                    Remarks = remarkText
                });
            }

            return rows;
        }

        private void GetRoomInternalDimensions(Room room, out double lengthMeters, out double widthMeters)
        {
            lengthMeters = 0.0;
            widthMeters = 0.0;

            BoundingBoxXYZ box = room.get_BoundingBox(null);
            if (box != null)
            {
                lengthMeters = UnitUtils.ConvertFromInternalUnits(Math.Abs(box.Max.X - box.Min.X), UnitTypeId.Meters);
                widthMeters = UnitUtils.ConvertFromInternalUnits(Math.Abs(box.Max.Y - box.Min.Y), UnitTypeId.Meters);
            }

            if (lengthMeters <= 0 || widthMeters <= 0)
            {
                double areaSqMeters = UnitUtils.ConvertFromInternalUnits(room.Area, UnitTypeId.SquareMeters);
                if (areaSqMeters > 0)
                {
                    lengthMeters = Math.Sqrt(areaSqMeters);
                    widthMeters = Math.Sqrt(areaSqMeters);
                }
                else
                {
                    lengthMeters = 4.0;
                    widthMeters = 3.0;
                }
            }
        }
    }
}