using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;

namespace RevitEstimate.ElectricalModule
{
    public partial class ElectricalEstimateWindow : Window
    {
        private Document _doc;
        public List<ElectricalFixtureConfig> HeightsSetup { get; set; }
        public List<RoomElectricalData> RoomElectricalMatrix { get; set; }
        private CollectionViewSource _roomViewSource;

        public ElectricalEstimateWindow(Document doc)
        {
            InitializeComponent();
            _doc = doc;
            LoadElectricalDataToUI();
        }

        private void LoadElectricalDataToUI()
        {
            // 1. Load Levels for Main DB / Panel Source
            var levels = new FilteredElementCollector(_doc).OfClass(typeof(Level)).Cast<Level>().OrderBy(l => l.Elevation).ToList();
            CmbPanelLevel.ItemsSource = levels;
            if (levels.Count > 0) CmbPanelLevel.SelectedIndex = 0;

            // 2. Load Standard Electrical Heights Config strictly in Millimeters (mm)
            HeightsSetup = new List<ElectricalFixtureConfig>
            {
                new ElectricalFixtureConfig { FixtureName = "Light & Fan Switch Board", HeightFromFFL_MM = 1500, Description = "Fitted at 1500 mm from FFL for general convenient operation." },
                new ElectricalFixtureConfig { FixtureName = "Bedside Switch Board", HeightFromFFL_MM = 750, Description = "Fitted at 750 mm near beds for easy bedside access." },
                new ElectricalFixtureConfig { FixtureName = "General 5-Pin Sockets", HeightFromFFL_MM = 1200, Description = "Placed at 1200 mm for general appliances and TV units." },
                new ElectricalFixtureConfig { FixtureName = "Kitchen Counter Outlets", HeightFromFFL_MM = 1200, Description = "Placed at 1200 mm from FFL / above kitchen slab for mixers and grinders." },
                new ElectricalFixtureConfig { FixtureName = "Heavy Power Sockets (AC, Geyser, WM)", HeightFromFFL_MM = 2100, Description = "Fitted at 2100 mm for heavy electrical loads and AC/Geysers." },
                new ElectricalFixtureConfig { FixtureName = "Distribution Box (DB / MCB Box)", HeightFromFFL_MM = 1500, Description = "Installed at 1500 mm for easy reach while keeping safe from children." }
            };
            GridElectricalHeights.ItemsSource = HeightsSetup;

            // 3. Scan Revit Rooms and Auto-Assign Electrical Fixtures
            var floors = new FilteredElementCollector(_doc).OfCategory(BuiltInCategory.OST_Floors).WhereElementIsNotElementType().Cast<Floor>().ToList();
            Dictionary<ElementId, double> levelSlabAreas = new Dictionary<ElementId, double>();
            foreach (var floor in floors)
            {
                ElementId levelId = floor.LevelId;
                double areaInt = floor.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED)?.AsDouble() ?? 0.0;
                double areaSqM = UnitUtils.ConvertFromInternalUnits(areaInt, UnitTypeId.SquareMeters);
                if (levelSlabAreas.ContainsKey(levelId)) levelSlabAreas[levelId] += areaSqM;
                else levelSlabAreas[levelId] = areaSqM;
            }

            var rooms = new FilteredElementCollector(_doc).OfCategory(BuiltInCategory.OST_Rooms).WhereElementIsNotElementType().Cast<Room>().Where(r => r.Area > 0).ToList();
            RoomElectricalMatrix = new List<RoomElectricalData>();
            var roomsByLevel = rooms.GroupBy(r => r.LevelId);

            int flatCounter = 1; double lastX = -999999;
            foreach (var levelGroup in roomsByLevel)
            {
                Level roomLevel = _doc.GetElement(levelGroup.Key) as Level;
                string levelName = roomLevel != null ? roomLevel.Name : "Unassigned";
                double elevMeters = roomLevel != null ? UnitUtils.ConvertFromInternalUnits(roomLevel.Elevation, UnitTypeId.Meters) : 0.0;
                double levelSlabArea = (roomLevel != null && levelSlabAreas.ContainsKey(roomLevel.Id))
                    ? levelSlabAreas[roomLevel.Id]
                    : levelGroup.Sum(r => UnitUtils.ConvertFromInternalUnits(r.Area, UnitTypeId.SquareMeters));

                var sortedRooms = levelGroup.OrderBy(r => { var bb = r.get_BoundingBox(null); return bb != null ? (bb.Min.X + bb.Max.X) / 2 : 0; }).ToList();

                foreach (var room in sortedRooms)
                {
                    var bb = room.get_BoundingBox(null);
                    double roomX = bb != null ? UnitUtils.ConvertFromInternalUnits((bb.Min.X + bb.Max.X) / 2, UnitTypeId.Meters) : 0;

                    if (lastX != -999999 && Math.Abs(roomX - lastX) > 12.0) flatCounter++;
                    lastX = roomX;

                    string nameLower = room.Name.ToLower();
                    bool isBed = nameLower.Contains("bed") || nameLower.Contains("master");
                    bool isLiving = nameLower.Contains("living") || nameLower.Contains("hall") || nameLower.Contains("drawing");
                    bool isKitchen = nameLower.Contains("kitchen");
                    bool isToilet = nameLower.Contains("toilet") || nameLower.Contains("bath") || nameLower.Contains("wc");
                    bool isBalcony = nameLower.Contains("balcony") || nameLower.Contains("open");

                    RoomElectricalMatrix.Add(new RoomElectricalData
                    {
                        LevelName = levelName,
                        FlatNumber = flatCounter,
                        IsFlatEnabled = true,
                        RoomTag = $"{room.Name} - {room.Number}",
                        RoomName = room.Name,
                        ZoneType = isBed ? "Bed Room" : (isLiving ? "Living Room" : (isKitchen ? "Kitchen" : (isToilet ? "Toilet / Bath" : "General Room"))),
                        SortOrder = isLiving ? 1 : (isBed ? 2 : (isKitchen ? 3 : 4)),
                        IsRoomActive = !isBalcony,
                        FloorElevation = elevMeters,
                        RoomArea = levelSlabArea,

                        // Auto-assigned quantities based on room category
                        LightPointQty = isLiving ? 4 : (isBed ? 3 : 2),
                        CeilingFanQty = (isLiving || isBed) ? 1 : 0,
                        WallFanQty = isKitchen ? 1 : 0,
                        LightFanSwitchBoardQty = (isLiving || isBed) ? 2 : 1,
                        BedsideSwitchBoardQty = isBed ? 2 : 0,
                        General5PinSocketQty = isLiving ? 3 : (isBed ? 2 : 1),
                        KitchenCounterSocketQty = isKitchen ? 2 : 0,
                        HeavyPowerSocketQty = (isKitchen || isBed) ? 1 : 0, // AC / Geyser / Power
                        DbBoxQty = (isLiving && flatCounter == 1) ? 1 : 0
                    });
                }
            }

            // 4. Add "Outside Porch" at the end of the Room Matrix for outer lights & fixtures
            string topLevelName = levels.LastOrDefault()?.Name ?? "Roof / Ground Level";
            double topElev = levels.LastOrDefault() != null ? UnitUtils.ConvertFromInternalUnits(levels.LastOrDefault().Elevation, UnitTypeId.Meters) : 0.0;

            RoomElectricalMatrix.Add(new RoomElectricalData
            {
                LevelName = topLevelName,
                FlatNumber = flatCounter > 0 ? flatCounter : 1,
                IsFlatEnabled = true,
                RoomTag = "Outside Porch / Exterior",
                RoomName = "Outside Porch",
                ZoneType = "Exterior",
                SortOrder = 99, // Ensures it appears at the bottom
                IsRoomActive = true,
                FloorElevation = topElev,
                RoomArea = 0.0,
                LightPointQty = 4, // Outer boundary/porch lights
                CeilingFanQty = 1,
                WallFanQty = 0,
                LightFanSwitchBoardQty = 1,
                BedsideSwitchBoardQty = 0,
                General5PinSocketQty = 1,
                KitchenCounterSocketQty = 0,
                HeavyPowerSocketQty = 0,
                DbBoxQty = 0
            });

            var sortedList = RoomElectricalMatrix.OrderBy(r => r.FloorElevation).ThenBy(r => r.FlatNumber).ThenBy(r => r.SortOrder).ToList();
            _roomViewSource = new CollectionViewSource { Source = sortedList };
            _roomViewSource.GroupDescriptions.Add(new PropertyGroupDescription("FlatHeader"));
            GridRoomElectricalMatrix.ItemsSource = _roomViewSource.View;
        }

        private void FlatToggle_Click(object sender, RoutedEventArgs e)
        {
            if (sender is CheckBox chk && chk.DataContext is CollectionViewGroup group)
            {
                bool isChecked = chk.IsChecked ?? false;
                foreach (RoomElectricalData item in group.Items) item.IsFlatEnabled = isChecked;
                GridRoomElectricalMatrix.Items.Refresh();
            }
        }

        private void BtnGenerateElectricalEstimate_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Floor to Floor height assumed 3.0 meters for general calculation drops
                double standardFloorHeight = 3.0;

                // Call the DSR Calculator method
                var finalEstimate = ElectricalDsrCalculator.GenerateEstimate(RoomElectricalMatrix, standardFloorHeight);

                if (finalEstimate == null || finalEstimate.Count == 0)
                {
                    MessageBox.Show("No active rooms or electrical fixtures found to generate an estimate.", "Empty Data", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                // Open the Final Result Window and pass the calculated data
                ElectricalResultWindow resultWindow = new ElectricalResultWindow(finalEstimate);
                resultWindow.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error calculating estimate: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        // =========================================================
        // NEW ACTUAL QUANTITY CALCULATION (TAB 3 LOGIC)
        // =========================================================
        private void BtnCalculateActual_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var actualItems = new List<ActualElectricalItem>();

                var categoriesToScan = new List<BuiltInCategory>
                {
                    BuiltInCategory.OST_Conduit,
                    BuiltInCategory.OST_CableTray,
                    BuiltInCategory.OST_LightingFixtures,
                    BuiltInCategory.OST_ElectricalFixtures,
                    BuiltInCategory.OST_ElectricalEquipment,
                    BuiltInCategory.OST_LightingDevices,
                    BuiltInCategory.OST_FireAlarmDevices
                };

                var multiCategoryFilter = new ElementMulticategoryFilter(categoriesToScan);
                var collector = new FilteredElementCollector(_doc)
                    .WherePasses(multiCategoryFilter)
                    .WhereElementIsNotElementType()
                    .ToList();

                var groupedElements = collector.GroupBy(elem => new
                {
                    CatName = elem.Category?.Name ?? "Unknown",
                    TypeName = GetFamilyAndTypeName(elem)
                });

                foreach (var group in groupedElements)
                {
                    int count = 0;
                    double totalLength = 0;
                    bool isLinear = group.Key.CatName.Contains("Conduit") || group.Key.CatName.Contains("Cable Tray");

                    foreach (var elem in group)
                    {
                        count++;

                        if (isLinear)
                        {
                            Parameter lengthParam = elem.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH);
                            if (lengthParam != null && lengthParam.HasValue)
                            {
                                // Converts Revit's internal feet to Meters securely
                                totalLength += UnitUtils.ConvertFromInternalUnits(lengthParam.AsDouble(), UnitTypeId.Meters);
                            }
                        }
                    }

                    actualItems.Add(new ActualElectricalItem
                    {
                        Category = group.Key.CatName,
                        FamilyAndType = group.Key.TypeName,
                        Count = count,
                        TotalLengthMeter = isLinear ? totalLength : 0,
                        Unit = isLinear ? "Metre" : "Nos"
                    });
                }

                GridActualQuantities.ItemsSource = actualItems.OrderBy(x => x.Category).ThenBy(x => x.FamilyAndType).ToList();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error extracting actual quantities: {ex.Message}", "Processing Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private string GetFamilyAndTypeName(Element elem)
        {
            ElementType type = _doc.GetElement(elem.GetTypeId()) as ElementType;
            if (type != null)
            {
                return $"{type.FamilyName} - {type.Name}";
            }
            return elem.Name;
        }
    }
}