using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using RevitMCPBridge2026;
using RevitMCPBridge.Helpers;

namespace RevitMCPBridge
{
    /// <summary>
    /// Pattern-aware sheet generation methods based on construction document standards analysis.
    /// Supports 5 industry-standard patterns: A (Hyphen-Decimal), C (Three-Digit),
    /// C-Zero, C-Institutional, and D (Space-Decimal).
    ///
    /// Knowledge base built from analysis of 8 professional construction document sets
    /// covering 6 different architectural firms across FL, NC, and CA.
    /// </summary>
    public static class SheetPatternMethods
    {
        #region Pattern Database

        /// <summary>
        /// Firm-to-pattern mappings. Firm names are personal/client data and therefore
        /// NEVER ship in source — they are loaded from bridge_config.json
        /// (sheetPatterns.firmPrefixes: { "Firm Name": "patternId", ... }).
        /// </summary>
        private static Dictionary<string, string> FirmPatterns => BridgeConfig.FirmSheetPrefixes;

        /// <summary>
        /// Firm pattern rules extracted from real project analysis. These describe
        /// client projects, so they are loaded from bridge_config.json
        /// (sheetPatterns.extractedPatterns: { "patternId": { ...pattern spec... } })
        /// and never ship in source. Cached per config load.
        /// </summary>
        private static Dictionary<string, JObject> ExtractedFirmPatterns
        {
            get
            {
                var map = new Dictionary<string, JObject>(StringComparer.OrdinalIgnoreCase);
                foreach (var prop in BridgeConfig.ExtractedSheetPatterns.Properties())
                {
                    if (prop.Value is JObject obj) map[prop.Name] = obj;
                }
                return map;
            }
        }

        /// <summary>
        /// Complete pattern specifications with rules and examples.
        /// These are GENERIC industry numbering patterns only — firm names and
        /// licensed-professional attributions belong in bridge_config.json
        /// (sheetPatterns.patternRuleOverrides), never in source.
        /// </summary>
        private static readonly Dictionary<string, JObject> BuiltInPatternRules = new Dictionary<string, JObject>
        {
            {"A", JObject.Parse(@"{
                ""name"": ""Hyphen-Decimal (Traditional)"",
                ""format"": ""{prefix}-{category}.{sequence}"",
                ""multiFloor"": ""sequential_decimal"",
                ""multiFloorExample"": ""A-1.1, A-1.2, A-1.3, A-1.4"",
                ""separator"": ""-"",
                ""description"": ""Traditional residential pattern used in Florida. One sheet per floor with sequential decimals."",
                ""firms"": [],
                ""regions"": [""FL""],
                ""projectTypes"": [""Residential"", ""Multi-family"", ""Interior upgrades""],
                ""sheetCategories"": {
                    ""cover"": ""G-00"",
                    ""sitePlan"": ""SP1"",
                    ""floorPlan"": ""A-1.x"",
                    ""elevations"": ""A-2.x"",
                    ""sections"": ""A-3.x"",
                    ""details"": ""A-5.x"",
                    ""structural"": ""S1, S2"",
                    ""mechanical"": ""M1, M2"",
                    ""electrical"": ""E1, E2"",
                    ""plumbing"": ""P1, P2""
                }
            }")},
            {"C", JObject.Parse(@"{
                ""name"": ""Three-Digit Sequential (Professional)"",
                ""format"": ""{discipline}{hundreds}{sequence}"",
                ""multiFloor"": ""separate_sheets_or_hundreds"",
                ""multiBuilding"": ""hundreds_based"",
                ""multiFloorExample"": ""A105, A106, A107"",
                ""multiBuildingExample"": ""A101-A199 (Building 1), A201-A299 (Building 2)"",
                ""description"": ""Professional/commercial standard. Most scalable pattern with 99 sheets per hundred-series."",
                ""firms"": [""Professional Standard"", ""Revit 2026 users""],
                ""regions"": [""Various""],
                ""projectTypes"": [""Professional"", ""Commercial"", ""Multi-building""],
                ""sheetCategories"": {
                    ""cover"": ""A101"",
                    ""sitePlan"": ""A103"",
                    ""floorPlans"": ""A105-A107"",
                    ""rcpPlans"": ""A107-A109"",
                    ""elevations"": ""A108-A109"",
                    ""sections"": ""A110-A111"",
                    ""details"": ""A112-A117"",
                    ""structural"": ""S101-S199"",
                    ""mechanical"": ""M101-M199"",
                    ""electrical"": ""E101-E199""
                },
                ""notes"": [""Gaps are acceptable (A113 to A115)"", ""Do not renumber after deletions""]
            }")},
            {"C-Zero", JObject.Parse(@"{
                ""name"": ""Three-Digit with Zero Cover"",
                ""format"": ""{discipline}{000}"",
                ""coverSheet"": ""A000"",
                ""multiFloorExample"": ""A101, A102, A103"",
                ""description"": ""Variation of Pattern C using zero-based cover sheet. Common with Bluebeam users."",
                ""firms"": [""Bluebeam users"", ""Various""],
                ""regions"": [""Various""],
                ""projectTypes"": [""Small to medium residential""],
                ""sheetCategories"": {
                    ""cover"": ""A000"",
                    ""architectural"": ""A101+"",
                    ""structural"": ""S101+"",
                    ""electrical"": ""E101+""
                }
            }")},
            {"C-Institutional", JObject.Parse(@"{
                ""name"": ""Three-Digit Institutional (G-Prefix)"",
                ""format"": ""{discipline}{hundreds}{sequence}"",
                ""gPrefix"": true,
                ""bidAlternates"": true,
                ""dimensionedVariants"": true,
                ""multiFloorExample"": ""A101, A102, A103"",
                ""bidAlternateExample"": ""A103A, A111A"",
                ""dimensionedExample"": ""A101.1 (dimensioned floor plan)"",
                ""description"": ""Institutional/public projects with general sheets, bid alternates, and dimensioned variants."",
                ""firms"": [],
                ""regions"": [""NC""],
                ""projectTypes"": [""Institutional"", ""Public"", ""Libraries"", ""Government""],
                ""sheetCategories"": {
                    ""cover"": ""A000"",
                    ""general"": ""G001-G099"",
                    ""sitePlan"": ""A101"",
                    ""floorPlans"": ""A101-A103"",
                    ""dimensionedPlans"": ""A101.1, A102.1"",
                    ""rcpPlans"": ""A104-A106"",
                    ""elevations"": ""A107-A110"",
                    ""sections"": ""A111-A113"",
                    ""details"": ""A114+"",
                    ""bidAlternates"": ""A103A, A111A"",
                    ""fireProtection"": ""FP501-FP599""
                }
            }")},
            {"D", JObject.Parse(@"{
                ""name"": ""Space-Decimal"",
                ""format"": ""{discipline} {category}.{sequence}"",
                ""separator"": "" "",
                ""adminStart"": 0,
                ""multiFloorExample"": ""A2.1, A2.2, A2.3"",
                ""uniqueFeatures"": [""Space separator"", ""Zero-based admin"", ""Separate wall sections category""],
                ""description"": ""Unique pattern using space separator. Zero-based admin sheets with intentional category gaps."",
                ""firms"": [],
                ""regions"": [""FL""],
                ""projectTypes"": [""Single family residential""],
                ""sheetCategories"": {
                    ""admin"": ""A 0.0, A 0.1"",
                    ""sitePlan"": ""A1.0"",
                    ""floorPlans"": ""A2.1, A2.2, A2.3"",
                    ""rcpPlans"": ""A3.0, A3.1"",
                    ""elevations"": ""A5.0, A5.1"",
                    ""sections"": ""A7.0, A7.1"",
                    ""wallSections"": ""A8.0, A8.1, A8.2"",
                    ""details"": ""A9.0, A9.1""
                },
                ""notes"": [""Intentional gaps (A3 to A5, no A4)"", ""Space is critical identifier""]
            }")}
        };

        /// <summary>
        /// Pattern rules = the built-in generic patterns merged with per-pattern overrides
        /// from bridge_config.json (sheetPatterns.patternRuleOverrides). An override with
        /// the same pattern id replaces the built-in definition wholesale.
        /// </summary>
        private static Dictionary<string, JObject> PatternRules
        {
            get
            {
                var merged = new Dictionary<string, JObject>(BuiltInPatternRules);
                foreach (var prop in BridgeConfig.SheetPatternRuleOverrides.Properties())
                {
                    if (prop.Value is JObject obj) merged[prop.Name] = obj;
                }
                return merged;
            }
        }

        /// <summary>
        /// Display name for a pattern id, whichever database defines it.
        /// </summary>
        private static string PatternDisplayName(string patternId)
        {
            if (!string.IsNullOrEmpty(patternId))
            {
                if (PatternRules.TryGetValue(patternId, out var rules))
                    return rules["name"]?.ToString() ?? patternId;
                if (ExtractedFirmPatterns.TryGetValue(patternId, out var extracted))
                    return extracted["name"]?.ToString() ?? patternId;
            }
            return patternId ?? "";
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Detects the sheet numbering pattern based on firm name from project or title block.
        /// Returns pattern ID with confidence level.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: firmName (string) - Name of firm from title block or project info
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "pattern": "A"|"C"|"C-Zero"|"C-Institutional"|"D",
        ///   "firmMatched": "Matched firm name",
        ///   "confidence": "high"|"default",
        ///   "patternName": "Full pattern name"
        /// }
        /// </returns>
        [MCPMethod("detectSheetPattern", Category = "SheetPattern")]
        public static string DetectSheetPattern(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var firmName = parameters["firmName"]?.ToString();

                if (string.IsNullOrEmpty(firmName))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "firmName is required. Provide firm name from title block or project info."
                    });
                }

                // Search for matching firm (case-insensitive, partial matching)
                foreach (var kvp in FirmPatterns)
                {
                    if (firmName.IndexOf(kvp.Key, StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        var patternId = kvp.Value;

                        // First check ExtractedFirmPatterns (new patterns from real projects)
                        if (ExtractedFirmPatterns.TryGetValue(patternId, out var extractedRules))
                        {
                            var patternName = extractedRules["name"].ToString();
                            return JsonConvert.SerializeObject(new
                            {
                                success = true,
                                pattern = patternId,
                                firmMatched = kvp.Key,
                                confidence = "high",
                                patternName = patternName,
                                source = "extracted",
                                extractedFrom = extractedRules["extractedFrom"]?.ToString(),
                                message = $"Matched '{kvp.Key}' → Pattern {patternId}: {patternName}"
                            });
                        }

                        // Fall back to legacy PatternRules
                        if (PatternRules.TryGetValue(patternId, out var legacyRules))
                        {
                            var patternName = legacyRules["name"].ToString();
                            return JsonConvert.SerializeObject(new
                            {
                                success = true,
                                pattern = patternId,
                                firmMatched = kvp.Key,
                                confidence = "high",
                                patternName = patternName,
                                source = "legacy",
                                message = $"Matched '{kvp.Key}' → Pattern {patternId}: {patternName}"
                            });
                        }
                    }
                }

                // Default to Pattern C if no match (professional standard)
                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    pattern = "C",
                    firmMatched = "None - using professional standard",
                    confidence = "default",
                    patternName = "Three-Digit Sequential (Professional)",
                    message = "No firm match found. Defaulting to Pattern C (industry standard)"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Retrieves complete pattern rules and specifications for a given pattern.
        /// Returns format, examples, multi-floor strategies, sheet categories, and more.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: patternId (string) - Pattern identifier: "A", "C", "C-Zero", "C-Institutional", or "D"
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "patternId": "A",
        ///   "rules": { ...complete pattern specification... }
        /// }
        /// </returns>
        [MCPMethod("getPatternRules", Category = "SheetPattern")]
        public static string GetPatternRules(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var patternId = parameters["patternId"]?.ToString();

                if (string.IsNullOrEmpty(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "patternId is required. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                if (!PatternRules.ContainsKey(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Unknown pattern: {patternId}. Valid patterns: A, C, C-Zero, C-Institutional, D",
                        availablePatterns = PatternRules.Keys.ToList()
                    });
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    patternId = patternId,
                    rules = PatternRules[patternId]
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Generates floor plan sheet numbers based on pattern, floor count, and building number.
        /// Automatically applies correct numbering strategy per pattern.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: patternId (string) - Pattern identifier
        /// Optional: floorCount (int) - Number of floors (default: 1)
        /// Optional: buildingNumber (int) - Building number for multi-building projects (default: 1)
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "pattern": "A",
        ///   "floorCount": 4,
        ///   "buildingNumber": 1,
        ///   "sheetNumbers": ["A-1.1", "A-1.2", "A-1.3", "A-1.4"],
        ///   "strategy": "sequential_decimal"
        /// }
        /// </returns>
        [MCPMethod("generateFloorPlanSheets", Category = "SheetPattern")]
        public static string GenerateFloorPlanSheets(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var patternId = parameters["patternId"]?.ToString();
                var floorCount = parameters["floorCount"]?.ToObject<int>() ?? 1;
                var buildingNumber = parameters["buildingNumber"]?.ToObject<int>() ?? 1;

                if (string.IsNullOrEmpty(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "patternId is required. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                if (floorCount < 1)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "floorCount must be at least 1"
                    });
                }

                if (buildingNumber < 1)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "buildingNumber must be at least 1"
                    });
                }

                List<string> sheetNumbers = new List<string>();
                string strategy = "";

                switch (patternId)
                {
                    case "A":
                        // Pattern A: A-1.1, A-1.2, A-1.3, A-1.4
                        // One sheet per floor with sequential decimals
                        for (int i = 1; i <= floorCount; i++)
                        {
                            sheetNumbers.Add($"A-1.{i}");
                        }
                        strategy = "sequential_decimal";
                        break;

                    case "C":
                    case "C-Zero":
                    case "C-Institutional":
                        // Pattern C: Three-digit sequential
                        if (buildingNumber > 1)
                        {
                            // Multi-building: A201, A202, A203 (building 2)
                            // A301, A302, A303 (building 3), etc.
                            int baseNum = buildingNumber * 100;
                            for (int i = 1; i <= floorCount; i++)
                            {
                                sheetNumbers.Add($"A{baseNum + i:D3}");
                            }
                            strategy = "hundreds_based_multi_building";
                        }
                        else
                        {
                            // Single building: A105, A106, A107
                            // Starting at 105 (typical for floor plans in Pattern C)
                            for (int i = 0; i < floorCount; i++)
                            {
                                sheetNumbers.Add($"A{105 + i:D3}");
                            }
                            strategy = "sequential_from_105";
                        }
                        break;

                    case "D":
                        // Pattern D: A2.1, A2.2, A2.3
                        // Category 2 is for floor plans in the space-decimal style
                        for (int i = 1; i <= floorCount; i++)
                        {
                            sheetNumbers.Add($"A2.{i}");
                        }
                        strategy = "sequential_within_category";
                        break;

                    default:
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = $"Unknown pattern: {patternId}. Valid patterns: A, C, C-Zero, C-Institutional, D"
                        });
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    pattern = patternId,
                    floorCount = floorCount,
                    buildingNumber = buildingNumber,
                    sheetNumbers = sheetNumbers,
                    strategy = strategy,
                    message = $"Generated {sheetNumbers.Count} floor plan sheet numbers using {strategy} strategy"
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Generates a complete sheet set based on pattern and project configuration.
        /// Creates all standard sheet categories following pattern-specific rules.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: patternId (string) - Pattern identifier
        /// Optional: floorCount (int) - Number of floors (default: 1)
        /// Optional: buildingCount (int) - Number of buildings (default: 1)
        /// Optional: hasRCP (bool) - Include reflected ceiling plans (default: false)
        /// Optional: hasStructural (bool) - Include structural sheets (default: false)
        /// Optional: hasMEP (bool) - Include MEP sheets (default: false)
        /// Optional: hasDetails (bool) - Include detail sheets (default: true)
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "pattern": "A",
        ///   "sheetCount": 15,
        ///   "sheets": [
        ///     {"number": "G-00", "name": "Cover Sheet", "category": "cover"},
        ///     {"number": "A-1.1", "name": "Floor Plan - Level 1", "category": "floorPlan"}
        ///   ]
        /// }
        /// </returns>
        [MCPMethod("generateCompleteSheetSet", Category = "SheetPattern")]
        public static string GenerateCompleteSheetSet(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var patternId = parameters["patternId"]?.ToString();
                var floorCount = parameters["floorCount"]?.ToObject<int>() ?? 1;
                var buildingCount = parameters["buildingCount"]?.ToObject<int>() ?? 1;
                var hasRCP = parameters["hasRCP"]?.ToObject<bool>() ?? false;
                var hasStructural = parameters["hasStructural"]?.ToObject<bool>() ?? false;
                var hasMEP = parameters["hasMEP"]?.ToObject<bool>() ?? false;
                var hasDetails = parameters["hasDetails"]?.ToObject<bool>() ?? true;

                if (string.IsNullOrEmpty(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "patternId is required. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                if (!PatternRules.ContainsKey(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Unknown pattern: {patternId}. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                var sheets = new List<JObject>();

                // Generate sheets based on pattern
                switch (patternId)
                {
                    case "A":
                        // Cover sheet
                        sheets.Add(JObject.Parse("{\"number\": \"G-00\", \"name\": \"Cover Sheet\", \"category\": \"cover\"}"));

                        // Site plan
                        sheets.Add(JObject.Parse("{\"number\": \"SP1\", \"name\": \"Site Plan\", \"category\": \"sitePlan\"}"));

                        // Floor plans (one per floor)
                        for (int i = 1; i <= floorCount; i++)
                        {
                            sheets.Add(JObject.Parse($"{{\"number\": \"A-1.{i}\", \"name\": \"Floor Plan - Level {i}\", \"category\": \"floorPlan\"}}"));
                        }

                        // Elevations
                        sheets.Add(JObject.Parse("{\"number\": \"A-2.1\", \"name\": \"Exterior Elevations\", \"category\": \"elevations\"}"));

                        // Sections
                        sheets.Add(JObject.Parse("{\"number\": \"A-3.1\", \"name\": \"Building Sections\", \"category\": \"sections\"}"));

                        // Details
                        if (hasDetails)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"A-5.1\", \"name\": \"Architectural Details\", \"category\": \"details\"}"));
                        }

                        // Structural
                        if (hasStructural)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"S1\", \"name\": \"Structural Plan\", \"category\": \"structural\"}"));
                        }

                        // MEP
                        if (hasMEP)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"M1\", \"name\": \"Mechanical Plan\", \"category\": \"mechanical\"}"));
                            sheets.Add(JObject.Parse("{\"number\": \"E1\", \"name\": \"Electrical Plan\", \"category\": \"electrical\"}"));
                            sheets.Add(JObject.Parse("{\"number\": \"P1\", \"name\": \"Plumbing Plan\", \"category\": \"plumbing\"}"));
                        }
                        break;

                    case "C":
                    case "C-Zero":
                        // Cover sheet
                        string coverNum = patternId == "C-Zero" ? "A000" : "A101";
                        sheets.Add(JObject.Parse($"{{\"number\": \"{coverNum}\", \"name\": \"Cover Sheet\", \"category\": \"cover\"}}"));

                        int baseOffset = patternId == "C-Zero" ? 101 : 103;

                        for (int b = 1; b <= buildingCount; b++)
                        {
                            int buildingBase = b * 100;
                            string buildingSuffix = buildingCount > 1 ? $" - Building {b}" : "";

                            // Site plan (only for building 1)
                            if (b == 1)
                            {
                                sheets.Add(JObject.Parse($"{{\"number\": \"A{baseOffset:D3}\", \"name\": \"Site Plan\", \"category\": \"sitePlan\"}}"));
                            }

                            // Floor plans
                            int fpStart = b > 1 ? buildingBase + 1 : baseOffset + 2;
                            for (int i = 0; i < floorCount; i++)
                            {
                                int sheetNum = fpStart + i;
                                sheets.Add(JObject.Parse($"{{\"number\": \"A{sheetNum:D3}\", \"name\": \"Floor Plan - Level {i + 1}{buildingSuffix}\", \"category\": \"floorPlan\"}}"));
                            }

                            // RCP if requested
                            if (hasRCP)
                            {
                                int rcpStart = fpStart + floorCount;
                                for (int i = 0; i < floorCount; i++)
                                {
                                    int sheetNum = rcpStart + i;
                                    sheets.Add(JObject.Parse($"{{\"number\": \"A{sheetNum:D3}\", \"name\": \"Reflected Ceiling Plan - Level {i + 1}{buildingSuffix}\", \"category\": \"rcp\"}}"));
                                }
                            }

                            // Elevations
                            int elevStart = fpStart + floorCount + (hasRCP ? floorCount : 0);
                            sheets.Add(JObject.Parse($"{{\"number\": \"A{elevStart:D3}\", \"name\": \"Exterior Elevations{buildingSuffix}\", \"category\": \"elevations\"}}"));

                            // Sections
                            sheets.Add(JObject.Parse($"{{\"number\": \"A{elevStart + 2:D3}\", \"name\": \"Building Sections{buildingSuffix}\", \"category\": \"sections\"}}"));

                            // Details
                            if (hasDetails)
                            {
                                sheets.Add(JObject.Parse($"{{\"number\": \"A{elevStart + 4:D3}\", \"name\": \"Architectural Details{buildingSuffix}\", \"category\": \"details\"}}"));
                            }
                        }

                        // Structural (discipline-wide)
                        if (hasStructural)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"S101\", \"name\": \"Structural Cover\", \"category\": \"structural\"}"));
                            sheets.Add(JObject.Parse("{\"number\": \"S102\", \"name\": \"Foundation Plan\", \"category\": \"structural\"}"));
                        }

                        // MEP (discipline-wide)
                        if (hasMEP)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"M101\", \"name\": \"Mechanical Plans\", \"category\": \"mechanical\"}"));
                            sheets.Add(JObject.Parse("{\"number\": \"E101\", \"name\": \"Electrical Plans\", \"category\": \"electrical\"}"));
                        }
                        break;

                    case "C-Institutional":
                        // Cover sheet
                        sheets.Add(JObject.Parse("{\"number\": \"A000\", \"name\": \"Cover Sheet\", \"category\": \"cover\"}"));

                        // General sheets (G-prefix)
                        sheets.Add(JObject.Parse("{\"number\": \"G001\", \"name\": \"General Notes\", \"category\": \"general\"}"));

                        // Site plan
                        sheets.Add(JObject.Parse("{\"number\": \"A101\", \"name\": \"Site Plan\", \"category\": \"sitePlan\"}"));

                        // Floor plans with dimensioned variants
                        for (int i = 0; i < floorCount; i++)
                        {
                            int sheetNum = 101 + i + 1;
                            sheets.Add(JObject.Parse($"{{\"number\": \"A{sheetNum:D3}\", \"name\": \"Floor Plan - Level {i + 1}\", \"category\": \"floorPlan\"}}"));
                            sheets.Add(JObject.Parse($"{{\"number\": \"A{sheetNum:D3}.1\", \"name\": \"Dimensioned Floor Plan - Level {i + 1}\", \"category\": \"floorPlanDimensioned\"}}"));
                        }

                        // RCP
                        if (hasRCP)
                        {
                            int rcpStart = 104;
                            for (int i = 0; i < floorCount; i++)
                            {
                                sheets.Add(JObject.Parse($"{{\"number\": \"A{rcpStart + i:D3}\", \"name\": \"RCP - Level {i + 1}\", \"category\": \"rcp\"}}"));
                            }
                        }

                        // Elevations
                        sheets.Add(JObject.Parse("{\"number\": \"A107\", \"name\": \"Exterior Elevations\", \"category\": \"elevations\"}"));

                        // Sections
                        sheets.Add(JObject.Parse("{\"number\": \"A111\", \"name\": \"Building Sections\", \"category\": \"sections\"}"));

                        // Details
                        if (hasDetails)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"A114\", \"name\": \"Architectural Details\", \"category\": \"details\"}"));
                        }

                        // Fire protection
                        sheets.Add(JObject.Parse("{\"number\": \"FP501\", \"name\": \"Fire Protection Plan\", \"category\": \"fireProtection\"}"));
                        break;

                    case "D":
                        // Admin sheets (zero-based)
                        sheets.Add(JObject.Parse("{\"number\": \"A 0.0\", \"name\": \"Cover Sheet\", \"category\": \"admin\"}"));

                        // Site plan
                        sheets.Add(JObject.Parse("{\"number\": \"A1.0\", \"name\": \"Site Plan\", \"category\": \"sitePlan\"}"));

                        // Floor plans (category 2)
                        for (int i = 1; i <= floorCount; i++)
                        {
                            sheets.Add(JObject.Parse($"{{\"number\": \"A2.{i}\", \"name\": \"Floor Plan - Level {i}\", \"category\": \"floorPlan\"}}"));
                        }

                        // RCP (category 3)
                        if (hasRCP)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"A3.0\", \"name\": \"Reflected Ceiling Plan\", \"category\": \"rcp\"}"));
                        }

                        // Elevations (category 5 - note gap)
                        sheets.Add(JObject.Parse("{\"number\": \"A5.0\", \"name\": \"Exterior Elevations\", \"category\": \"elevations\"}"));

                        // Sections (category 7)
                        sheets.Add(JObject.Parse("{\"number\": \"A7.0\", \"name\": \"Building Sections\", \"category\": \"sections\"}"));

                        // Wall sections (category 8)
                        sheets.Add(JObject.Parse("{\"number\": \"A8.0\", \"name\": \"Wall Sections\", \"category\": \"wallSections\"}"));

                        // Details (category 9)
                        if (hasDetails)
                        {
                            sheets.Add(JObject.Parse("{\"number\": \"A9.0\", \"name\": \"Architectural Details\", \"category\": \"details\"}"));
                        }
                        break;

                    default:
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = $"Pattern {patternId} not fully implemented for complete sheet set generation"
                        });
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    pattern = patternId,
                    sheetCount = sheets.Count,
                    sheets = sheets,
                    message = $"Generated {sheets.Count} sheets for pattern {patternId}"
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Creates sheets in Revit based on a sheet list from GenerateCompleteSheetSet.
        /// Actually places ViewSheet objects in the document with proper numbering.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: sheets (array) - Array of sheet objects with "number" and "name" properties
        /// Optional: titleBlockId (string) - ElementId of title block to use (defaults to first available)
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "createdCount": 10,
        ///   "createdSheets": [
        ///     {"number": "A101", "name": "Cover Sheet", "id": "12345"},
        ///     ...
        ///   ],
        ///   "skippedCount": 2,
        ///   "skippedSheets": [...]
        /// }
        /// </returns>
        [MCPMethod("createSheetsFromPattern", Category = "SheetPattern")]
        public static string CreateSheetsFromPattern(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse sheet list
                var sheetsArray = parameters["sheets"] as JArray;
                if (sheetsArray == null || sheetsArray.Count == 0)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "sheets array is required and must contain at least one sheet"
                    });
                }

                // Get title block to use
                ElementId titleBlockId = null;
                if (parameters["titleBlockId"] != null)
                {
                    var titleBlockIdStr = parameters["titleBlockId"].ToString();
                    if (int.TryParse(titleBlockIdStr, out int tbId))
                    {
                        titleBlockId = new ElementId(tbId);
                    }
                }

                // If no title block specified, find first available
                if (titleBlockId == null || titleBlockId == ElementId.InvalidElementId)
                {
                    var titleBlocks = new FilteredElementCollector(doc)
                        .OfCategory(BuiltInCategory.OST_TitleBlocks)
                        .WhereElementIsElementType()
                        .ToList();

                    if (titleBlocks.Count == 0)
                    {
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "No title blocks found in project. Load a title block family first."
                        });
                    }

                    titleBlockId = titleBlocks[0].Id;
                }

                var createdSheets = new List<JObject>();
                var skippedSheets = new List<JObject>();

                using (var trans = new Transaction(doc, "Create Sheets from Pattern"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    foreach (var sheetObj in sheetsArray)
                    {
                        try
                        {
                            var sheetNumber = sheetObj["number"]?.ToString();
                            var sheetName = sheetObj["name"]?.ToString();

                            if (string.IsNullOrEmpty(sheetNumber))
                            {
                                skippedSheets.Add(JObject.Parse($"{{\"error\": \"Missing sheet number\", \"sheet\": {sheetObj}}}"));
                                continue;
                            }

                            // Check if sheet number already exists
                            var existingSheets = new FilteredElementCollector(doc)
                                .OfClass(typeof(ViewSheet))
                                .Cast<ViewSheet>()
                                .Where(s => s.SheetNumber == sheetNumber)
                                .ToList();

                            if (existingSheets.Any())
                            {
                                skippedSheets.Add(JObject.Parse($"{{\"number\": \"{sheetNumber}\", \"name\": \"{sheetName}\", \"reason\": \"Sheet number already exists\"}}"));
                                continue;
                            }

                            // Create new sheet
                            var newSheet = ViewSheet.Create(doc, titleBlockId);
                            newSheet.SheetNumber = sheetNumber;
                            if (!string.IsNullOrEmpty(sheetName))
                            {
                                newSheet.Name = sheetName;
                            }

                            createdSheets.Add(JObject.Parse($"{{\"number\": \"{sheetNumber}\", \"name\": \"{sheetName}\", \"id\": \"{newSheet.Id.Value}\"}}"));
                        }
                        catch (Exception ex)
                        {
                            skippedSheets.Add(JObject.Parse($"{{\"sheet\": {sheetObj}, \"error\": \"{ex.Message.Replace("\"", "'")}\"}}"));
                        }
                    }

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    createdCount = createdSheets.Count,
                    createdSheets = createdSheets,
                    skippedCount = skippedSheets.Count,
                    skippedSheets = skippedSheets,
                    message = $"Created {createdSheets.Count} sheets. Skipped {skippedSheets.Count} sheets."
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Creates/updates a client profile with pattern preference.
        /// Stores in project information for future reference.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: firmName (string) - Name of the firm/client
        /// Required: patternId (string) - Pattern to associate with this firm
        /// Optional: notes (string) - Additional notes about client preferences
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "firmName": "Smith Architecture",
        ///   "patternId": "C",
        ///   "message": "Client profile created/updated"
        /// }
        /// </returns>
        [MCPMethod("createClientProfile", Category = "SheetPattern")]
        public static string CreateClientProfile(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;
                var firmName = parameters["firmName"]?.ToString();
                var patternId = parameters["patternId"]?.ToString();
                var notes = parameters["notes"]?.ToString() ?? "";

                if (string.IsNullOrEmpty(firmName))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "firmName is required"
                    });
                }

                if (string.IsNullOrEmpty(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "patternId is required. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                if (!PatternRules.ContainsKey(patternId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Unknown pattern: {patternId}. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                // Store in project information parameter
                using (var trans = new Transaction(doc, "Create Client Profile"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    var projInfo = doc.ProjectInformation;

                    // Try to set client info parameter (if it exists)
                    // Note: This requires a "Client Firm" parameter on ProjectInformation
                    // For now, we'll just track in memory and return success
                    // In production, would use Extensible Storage or shared parameters

                    trans.CommitAndCheck();
                }

                // Add to in-memory database for this session
                if (!FirmPatterns.ContainsKey(firmName))
                {
                    // Note: This modifies static dictionary - in real implementation,
                    // would use extensible storage for persistence
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    firmName = firmName,
                    patternId = patternId,
                    notes = notes,
                    message = $"Client profile created for '{firmName}' with pattern {patternId}. Note: Persistence requires Extensible Storage implementation."
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Retrieves client profile based on firm name.
        /// Returns pattern preference and notes if available.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: firmName (string) - Name of firm to look up
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "firmName": "Smith Architecture",
        ///   "patternId": "C",
        ///   "patternName": "Three-Digit Sequential (Professional)",
        ///   "found": true
        /// }
        /// </returns>
        [MCPMethod("getClientProfile", Category = "SheetPattern")]
        public static string GetClientProfile(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var firmName = parameters["firmName"]?.ToString();

                if (string.IsNullOrEmpty(firmName))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "firmName is required"
                    });
                }

                // Search for matching firm in database
                foreach (var kvp in FirmPatterns)
                {
                    if (firmName.IndexOf(kvp.Key, StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        var patternId = kvp.Value;
                        var patternName = PatternDisplayName(patternId);

                        return JsonConvert.SerializeObject(new
                        {
                            success = true,
                            found = true,
                            firmName = kvp.Key,
                            patternId = patternId,
                            patternName = patternName,
                            message = $"Found profile for '{kvp.Key}' → Pattern {patternId}"
                        });
                    }
                }

                // Not found
                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    found = false,
                    firmName = firmName,
                    message = $"No profile found for '{firmName}'. Will use default Pattern C."
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Lists all known firms and their pattern associations.
        /// Returns complete catalog from the pattern database.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">No parameters required</param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true,
        ///   "firmCount": 11,
        ///   "firms": [
        ///     {"name": "Smith Architecture", "pattern": "A", "patternName": "Hyphen-Decimal"},
        ///     ...
        ///   ]
        /// }
        /// </returns>
        [MCPMethod("listKnownFirms", Category = "SheetPattern")]
        public static string ListKnownFirms(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var firms = new List<JObject>();

                foreach (var kvp in FirmPatterns)
                {
                    var patternName = PatternDisplayName(kvp.Value);
                    firms.Add(JObject.Parse($"{{\"name\": \"{kvp.Key}\", \"pattern\": \"{kvp.Value}\", \"patternName\": \"{patternName}\"}}"));
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    firmCount = firms.Count,
                    firms = firms,
                    message = $"Cataloged {firms.Count} firm pattern associations"
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Analyzes existing sheets in the project to detect which pattern is being used.
        /// Examines sheet numbering format to identify Pattern A, C, C-Zero, C-Institutional, or D.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">No parameters required</param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "detectedPattern": "C",
        ///   "confidence": "high",
        ///   "sheetCount": 15,
        ///   "samples": ["A101", "A102", "A103"],
        ///   "reasoning": "Three-digit sequential format detected"
        /// }
        /// </returns>
        [MCPMethod("detectExistingPattern", Category = "SheetPattern")]
        public static string DetectExistingPattern(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Get all sheets
                var sheets = new FilteredElementCollector(doc)
                    .OfClass(typeof(ViewSheet))
                    .Cast<ViewSheet>()
                    .Where(s => !s.IsPlaceholder)
                    .ToList();

                if (sheets.Count == 0)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        detectedPattern = "None",
                        confidence = "n/a",
                        sheetCount = 0,
                        message = "No sheets found in project"
                    });
                }

                // Collect sheet numbers for analysis
                var sheetNumbers = sheets.Select(s => s.SheetNumber).ToList();
                var samples = sheetNumbers.Take(5).ToList();

                // Pattern detection logic
                int patternACount = 0;
                int patternCCount = 0;
                int patternCZeroCount = 0;
                int patternCInstCount = 0;
                int patternDCount = 0;

                foreach (var num in sheetNumbers)
                {
                    // Pattern A: Contains hyphen (A-1.1, G-00, SP1)
                    if (num.Contains("-"))
                    {
                        patternACount++;
                    }
                    // Pattern D: Contains space (A 0.0, A2.1)
                    else if (num.Contains(" "))
                    {
                        patternDCount++;
                    }
                    // Pattern C-Zero: A000 format
                    else if (num.Length >= 4 && num.Substring(1, 3) == "000")
                    {
                        patternCZeroCount++;
                    }
                    // Pattern C-Institutional: G-prefix or FP-prefix
                    else if (num.StartsWith("G") || num.StartsWith("FP") || num.Contains("."))
                    {
                        patternCInstCount++;
                    }
                    // Pattern C: Three-digit (A101, A102, S101)
                    else if (num.Length >= 4 && char.IsDigit(num[1]))
                    {
                        patternCCount++;
                    }
                }

                // Determine dominant pattern
                string detectedPattern = "C"; // Default
                string confidence = "medium";
                string reasoning = "";

                int maxCount = Math.Max(Math.Max(Math.Max(Math.Max(patternACount, patternCCount), patternCZeroCount), patternCInstCount), patternDCount);

                if (maxCount == patternACount && patternACount > 0)
                {
                    detectedPattern = "A";
                    reasoning = $"Hyphen-decimal format detected in {patternACount} of {sheetNumbers.Count} sheets";
                    confidence = patternACount > sheetNumbers.Count / 2 ? "high" : "medium";
                }
                else if (maxCount == patternDCount && patternDCount > 0)
                {
                    detectedPattern = "D";
                    reasoning = $"Space-decimal format detected in {patternDCount} of {sheetNumbers.Count} sheets";
                    confidence = patternDCount > sheetNumbers.Count / 2 ? "high" : "medium";
                }
                else if (maxCount == patternCInstCount && patternCInstCount > 0)
                {
                    detectedPattern = "C-Institutional";
                    reasoning = $"Institutional format (G-prefix/decimals) detected in {patternCInstCount} of {sheetNumbers.Count} sheets";
                    confidence = patternCInstCount > sheetNumbers.Count / 2 ? "high" : "medium";
                }
                else if (maxCount == patternCZeroCount && patternCZeroCount > 0)
                {
                    detectedPattern = "C-Zero";
                    reasoning = $"Zero-based cover format detected in {patternCZeroCount} of {sheetNumbers.Count} sheets";
                    confidence = "medium";
                }
                else if (patternCCount > 0)
                {
                    detectedPattern = "C";
                    reasoning = $"Three-digit sequential format detected in {patternCCount} of {sheetNumbers.Count} sheets";
                    confidence = patternCCount > sheetNumbers.Count / 2 ? "high" : "medium";
                }
                else
                {
                    detectedPattern = "C";
                    reasoning = "Unable to determine pattern, defaulting to professional standard (Pattern C)";
                    confidence = "low";
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    detectedPattern = detectedPattern,
                    confidence = confidence,
                    sheetCount = sheetNumbers.Count,
                    samples = samples,
                    reasoning = reasoning,
                    patternCounts = new
                    {
                        patternA = patternACount,
                        patternC = patternCCount,
                        patternCZero = patternCZeroCount,
                        patternCInstitutional = patternCInstCount,
                        patternD = patternDCount
                    }
                }, Formatting.Indented);
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Suggests the next sheet number based on existing sheets and pattern.
        /// Analyzes gaps and follows pattern rules.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: category (string) - Sheet category (floorPlan, elevations, etc.)
        /// Optional: patternId (string) - Pattern to use (auto-detected if not provided)
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "suggestedNumber": "A108",
        ///   "category": "floorPlan",
        ///   "reasoning": "Next sequential number after A107"
        /// }
        /// </returns>
        [MCPMethod("suggestNextSheetNumber", Category = "SheetPattern")]
        public static string SuggestNextSheetNumber(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;
                var category = parameters["category"]?.ToString();
                var patternId = parameters["patternId"]?.ToString();

                if (string.IsNullOrEmpty(category))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "category is required (e.g., floorPlan, elevations, sections, details)"
                    });
                }

                // Auto-detect pattern if not provided
                if (string.IsNullOrEmpty(patternId))
                {
                    var detectResult = DetectExistingPattern(uiApp, new JObject());
                    var detectObj = JObject.Parse(detectResult);
                    patternId = detectObj["detectedPattern"]?.ToString() ?? "C";
                }

                // Get all sheets
                var sheets = new FilteredElementCollector(doc)
                    .OfClass(typeof(ViewSheet))
                    .Cast<ViewSheet>()
                    .Where(s => !s.IsPlaceholder)
                    .Select(s => s.SheetNumber)
                    .ToList();

                string suggestedNumber = "";
                string reasoning = "";

                // Pattern-specific logic
                switch (patternId)
                {
                    case "A":
                        if (category == "floorPlan")
                        {
                            var floorSheets = sheets.Where(s => s.StartsWith("A-1.")).ToList();
                            int maxFloor = 0;
                            foreach (var s in floorSheets)
                            {
                                var parts = s.Split('.');
                                if (parts.Length == 2 && int.TryParse(parts[1], out int floor))
                                {
                                    maxFloor = Math.Max(maxFloor, floor);
                                }
                            }
                            suggestedNumber = $"A-1.{maxFloor + 1}";
                            reasoning = $"Next floor plan after A-1.{maxFloor}";
                        }
                        else
                        {
                            suggestedNumber = "A-2.1";
                            reasoning = "Standard number for elevations in Pattern A";
                        }
                        break;

                    case "C":
                    case "C-Zero":
                    case "C-Institutional":
                        var archSheets = sheets.Where(s => s.StartsWith("A") && char.IsDigit(s[1])).ToList();
                        int maxNum = 100;
                        foreach (var s in archSheets)
                        {
                            if (int.TryParse(s.Substring(1), out int num))
                            {
                                maxNum = Math.Max(maxNum, num);
                            }
                        }
                        suggestedNumber = $"A{maxNum + 1:D3}";
                        reasoning = $"Next sequential number after A{maxNum:D3}";
                        break;

                    case "D":
                        if (category == "floorPlan")
                        {
                            var floorSheets = sheets.Where(s => s.StartsWith("A2.")).ToList();
                            int maxFloor = 0;
                            foreach (var s in floorSheets)
                            {
                                var parts = s.Split('.');
                                if (parts.Length == 2 && int.TryParse(parts[1], out int floor))
                                {
                                    maxFloor = Math.Max(maxFloor, floor);
                                }
                            }
                            suggestedNumber = $"A2.{maxFloor + 1}";
                            reasoning = $"Next floor plan after A2.{maxFloor}";
                        }
                        else
                        {
                            suggestedNumber = "A5.0";
                            reasoning = "Standard number for elevations in Pattern D";
                        }
                        break;

                    default:
                        suggestedNumber = "A101";
                        reasoning = "Default suggestion - Pattern C standard";
                        break;
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    suggestedNumber = suggestedNumber,
                    category = category,
                    pattern = patternId,
                    reasoning = reasoning,
                    message = $"Suggested: {suggestedNumber} ({reasoning})"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Converts sheet numbers from one pattern to another.
        /// Provides warnings about incompatible conversions.
        /// </summary>
        /// <param name="uiApp">Revit UI Application</param>
        /// <param name="parameters">
        /// Required: fromPattern (string) - Source pattern
        /// Required: toPattern (string) - Target pattern
        /// Required: sheetNumber (string) - Sheet number to convert
        /// </param>
        /// <returns>
        /// JSON object:
        /// {
        ///   "success": true/false,
        ///   "originalNumber": "A-1.1",
        ///   "convertedNumber": "A105",
        ///   "fromPattern": "A",
        ///   "toPattern": "C",
        ///   "warnings": ["Floor-specific numbering converted to sequential"]
        /// }
        /// </returns>
        [MCPMethod("convertBetweenPatterns", Category = "SheetPattern")]
        public static string ConvertBetweenPatterns(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var fromPattern = parameters["fromPattern"]?.ToString();
                var toPattern = parameters["toPattern"]?.ToString();
                var sheetNumber = parameters["sheetNumber"]?.ToString();

                if (string.IsNullOrEmpty(fromPattern) || string.IsNullOrEmpty(toPattern) || string.IsNullOrEmpty(sheetNumber))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "fromPattern, toPattern, and sheetNumber are all required"
                    });
                }

                if (!PatternRules.ContainsKey(fromPattern) || !PatternRules.ContainsKey(toPattern))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Invalid pattern. Valid patterns: A, C, C-Zero, C-Institutional, D"
                    });
                }

                string convertedNumber = sheetNumber;
                var warnings = new List<string>();

                // Same pattern - no conversion needed
                if (fromPattern == toPattern)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        originalNumber = sheetNumber,
                        convertedNumber = sheetNumber,
                        fromPattern = fromPattern,
                        toPattern = toPattern,
                        warnings = new[] { "No conversion needed - patterns are identical" }
                    });
                }

                // Pattern A → C conversion
                if (fromPattern == "A" && (toPattern == "C" || toPattern == "C-Zero"))
                {
                    if (sheetNumber.Contains("-1."))
                    {
                        // A-1.1 → A105, A-1.2 → A106
                        var parts = sheetNumber.Split('.');
                        if (parts.Length == 2 && int.TryParse(parts[1], out int floor))
                        {
                            convertedNumber = $"A{104 + floor:D3}";
                            warnings.Add("Floor-specific numbering converted to sequential starting at A105");
                        }
                    }
                    else if (sheetNumber == "G-00")
                    {
                        convertedNumber = toPattern == "C-Zero" ? "A000" : "A101";
                        warnings.Add("Cover sheet converted");
                    }
                    else if (sheetNumber == "SP1")
                    {
                        convertedNumber = "A103";
                        warnings.Add("Site plan converted to A103");
                    }
                }
                // Pattern C → A conversion
                else if ((fromPattern == "C" || fromPattern == "C-Zero") && toPattern == "A")
                {
                    if (sheetNumber.StartsWith("A10") || sheetNumber.StartsWith("A11"))
                    {
                        // A105-A108 → A-1.1, A-1.2, etc.
                        if (int.TryParse(sheetNumber.Substring(1), out int num))
                        {
                            int floor = num - 104;
                            if (floor > 0)
                            {
                                convertedNumber = $"A-1.{floor}";
                                warnings.Add("Sequential numbering converted to floor-specific");
                            }
                        }
                    }
                    else if (sheetNumber == "A101" || sheetNumber == "A000")
                    {
                        convertedNumber = "G-00";
                        warnings.Add("Cover sheet converted");
                    }
                }
                // Pattern D conversions
                else if (fromPattern == "D" || toPattern == "D")
                {
                    warnings.Add("Pattern D uses unique space separator - manual verification recommended");
                    if (fromPattern == "D" && sheetNumber.StartsWith("A2."))
                    {
                        var parts = sheetNumber.Split('.');
                        if (parts.Length == 2 && int.TryParse(parts[1], out int floor))
                        {
                            convertedNumber = toPattern == "A" ? $"A-1.{floor}" : $"A{104 + floor:D3}";
                        }
                    }
                }
                else
                {
                    warnings.Add("Complex conversion - manual verification required");
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    originalNumber = sheetNumber,
                    convertedNumber = convertedNumber,
                    fromPattern = fromPattern,
                    toPattern = toPattern,
                    warnings = warnings,
                    message = $"Converted {sheetNumber} ({fromPattern}) → {convertedNumber} ({toPattern})"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        #endregion

        #region Guide Grid Methods

        /// <summary>
        /// Gets all guide grids in the document by scanning sheets for assigned guide grids
        /// Note: GuideGrid class is not publicly accessible in Revit 2026, so we use parameter-based approach
        /// </summary>
        [MCPMethod("getGuideGrids", Category = "SheetPattern")]
        public static string GetGuideGrids(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;
                var guideGrids = new Dictionary<long, object>();

                // Scan all sheets to find guide grids via their parameters
                var sheets = new FilteredElementCollector(doc)
                    .OfClass(typeof(ViewSheet))
                    .Cast<ViewSheet>()
                    .ToList();

                foreach (var sheet in sheets)
                {
                    var guideGridParam = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                    if (guideGridParam != null && guideGridParam.HasValue)
                    {
                        var guideGridId = guideGridParam.AsElementId();
                        if (guideGridId != null && guideGridId != ElementId.InvalidElementId)
                        {
                            var guideGridElement = doc.GetElement(guideGridId);
                            if (guideGridElement != null && !guideGrids.ContainsKey(guideGridId.Value))
                            {
                                // Get bounding box for size estimation
                                var bbox = guideGridElement.get_BoundingBox(sheet);
                                double? width = null, height = null;
                                if (bbox != null)
                                {
                                    width = bbox.Max.X - bbox.Min.X;
                                    height = bbox.Max.Y - bbox.Min.Y;
                                }

                                guideGrids[guideGridId.Value] = new
                                {
                                    id = guideGridId.Value,
                                    name = guideGridElement.Name,
                                    width = width,
                                    height = height,
                                    widthInches = width * 12,
                                    heightInches = height * 12
                                };
                            }
                        }
                    }
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    count = guideGrids.Count,
                    guideGrids = guideGrids.Values.ToList(),
                    note = "Guide grids must be created manually in Revit. This method lists existing grids found on sheets."
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Gets guide grid info for a specific sheet
        /// </summary>
        [MCPMethod("getSheetGuideGrid", Category = "SheetPattern")]
        public static string GetSheetGuideGrid(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["sheetId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "sheetId is required"
                    });
                }

                long sheetIdLong = parameters["sheetId"].ToObject<long>();
                var sheet = doc.GetElement(new ElementId(sheetIdLong)) as ViewSheet;

                if (sheet == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Sheet with ID {sheetIdLong} not found"
                    });
                }

                var guideGridParam = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                if (guideGridParam == null || !guideGridParam.HasValue)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        sheetId = sheetIdLong,
                        sheetNumber = sheet.SheetNumber,
                        hasGuideGrid = false,
                        guideGridId = (long?)null,
                        guideGridName = (string)null
                    });
                }

                var guideGridId = guideGridParam.AsElementId();
                if (guideGridId == null || guideGridId == ElementId.InvalidElementId)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        sheetId = sheetIdLong,
                        sheetNumber = sheet.SheetNumber,
                        hasGuideGrid = false,
                        guideGridId = (long?)null,
                        guideGridName = (string)null
                    });
                }

                var guideGridElement = doc.GetElement(guideGridId);
                var bbox = guideGridElement?.get_BoundingBox(sheet);

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    sheetId = sheetIdLong,
                    sheetNumber = sheet.SheetNumber,
                    hasGuideGrid = true,
                    guideGridId = guideGridId.Value,
                    guideGridName = guideGridElement?.Name,
                    bounds = bbox != null ? new
                    {
                        minX = bbox.Min.X,
                        minY = bbox.Min.Y,
                        maxX = bbox.Max.X,
                        maxY = bbox.Max.Y,
                        width = bbox.Max.X - bbox.Min.X,
                        height = bbox.Max.Y - bbox.Min.Y
                    } : null
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Applies a guide grid to a sheet using the SHEET_GUIDE_GRID parameter
        /// </summary>
        [MCPMethod("applyGuideGridToSheet", Category = "SheetPattern")]
        public static string ApplyGuideGridToSheet(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["sheetId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "sheetId is required"
                    });
                }

                if (parameters["guideGridId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "guideGridId is required"
                    });
                }

                long sheetIdLong = parameters["sheetId"].ToObject<long>();
                long gridIdLong = parameters["guideGridId"].ToObject<long>();

                var sheet = doc.GetElement(new ElementId(sheetIdLong)) as ViewSheet;
                if (sheet == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Sheet with ID {sheetIdLong} not found"
                    });
                }

                var guideGridElement = doc.GetElement(new ElementId(gridIdLong));
                if (guideGridElement == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Guide grid with ID {gridIdLong} not found"
                    });
                }

                var guideGridParam = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                if (guideGridParam == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Sheet does not support guide grid parameter"
                    });
                }

                using (var trans = new Transaction(doc, "Apply Guide Grid to Sheet"))
                {
                    trans.Start();
                    guideGridParam.Set(new ElementId(gridIdLong));
                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    sheetId = sheetIdLong,
                    sheetNumber = sheet.SheetNumber,
                    sheetName = sheet.Name,
                    guideGridId = gridIdLong,
                    guideGridName = guideGridElement.Name,
                    message = $"Applied guide grid '{guideGridElement.Name}' to sheet {sheet.SheetNumber}"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Applies a guide grid to multiple sheets
        /// </summary>
        [MCPMethod("applyGuideGridToSheets", Category = "SheetPattern")]
        public static string ApplyGuideGridToSheets(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["guideGridId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "guideGridId is required"
                    });
                }

                long gridIdLong = parameters["guideGridId"].ToObject<long>();
                var guideGridElement = doc.GetElement(new ElementId(gridIdLong));

                if (guideGridElement == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Guide grid with ID {gridIdLong} not found"
                    });
                }

                // Get sheets - by IDs or by pattern
                var sheetIds = new List<ElementId>();

                if (parameters["sheetIds"] != null)
                {
                    var ids = parameters["sheetIds"].ToObject<List<long>>();
                    sheetIds = ids.Select(id => new ElementId(id)).ToList();
                }
                else if (parameters["sheetNumberPattern"] != null)
                {
                    string pattern = parameters["sheetNumberPattern"].ToString();
                    var sheets = new FilteredElementCollector(doc)
                        .OfClass(typeof(ViewSheet))
                        .Cast<ViewSheet>()
                        .Where(s => s.SheetNumber.StartsWith(pattern))
                        .ToList();
                    sheetIds = sheets.Select(s => s.Id).ToList();
                }
                else
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Provide sheetIds array or sheetNumberPattern"
                    });
                }

                var results = new List<object>();
                int successCount = 0;

                using (var trans = new Transaction(doc, "Apply Guide Grid to Multiple Sheets"))
                {
                    trans.Start();

                    foreach (var sheetId in sheetIds)
                    {
                        var sheet = doc.GetElement(sheetId) as ViewSheet;
                        if (sheet != null)
                        {
                            var guideGridParam = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                            if (guideGridParam != null)
                            {
                                guideGridParam.Set(new ElementId(gridIdLong));
                                results.Add(new
                                {
                                    sheetId = sheetId.Value,
                                    sheetNumber = sheet.SheetNumber,
                                    success = true
                                });
                                successCount++;
                            }
                            else
                            {
                                results.Add(new
                                {
                                    sheetId = sheetId.Value,
                                    sheetNumber = sheet.SheetNumber,
                                    success = false,
                                    error = "Guide grid parameter not available"
                                });
                            }
                        }
                        else
                        {
                            results.Add(new
                            {
                                sheetId = sheetId.Value,
                                success = false,
                                error = "Sheet not found"
                            });
                        }
                    }

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    guideGridName = guideGridElement.Name,
                    totalSheets = sheetIds.Count,
                    successCount = successCount,
                    results = results,
                    message = $"Applied guide grid '{guideGridElement.Name}' to {successCount} sheets"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Removes guide grid from a sheet (sets to none)
        /// </summary>
        [MCPMethod("removeGuideGridFromSheet", Category = "SheetPattern")]
        public static string RemoveGuideGridFromSheet(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["sheetId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "sheetId is required"
                    });
                }

                long sheetIdLong = parameters["sheetId"].ToObject<long>();
                var sheet = doc.GetElement(new ElementId(sheetIdLong)) as ViewSheet;

                if (sheet == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Sheet with ID {sheetIdLong} not found"
                    });
                }

                var guideGridParam = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                string oldGridName = "None";

                if (guideGridParam != null && guideGridParam.HasValue)
                {
                    var oldGridId = guideGridParam.AsElementId();
                    if (oldGridId != ElementId.InvalidElementId)
                    {
                        var oldGrid = doc.GetElement(oldGridId);
                        if (oldGrid != null) oldGridName = oldGrid.Name;
                    }
                }

                using (var trans = new Transaction(doc, "Remove Guide Grid from Sheet"))
                {
                    trans.Start();

                    if (guideGridParam != null)
                    {
                        guideGridParam.Set(ElementId.InvalidElementId);
                    }

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    sheetId = sheetIdLong,
                    sheetNumber = sheet.SheetNumber,
                    removedGridName = oldGridName,
                    message = $"Removed guide grid '{oldGridName}' from sheet {sheet.SheetNumber}"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Deletes a guide grid element from the document
        /// </summary>
        [MCPMethod("deleteGuideGrid", Category = "SheetPattern")]
        public static string DeleteGuideGrid(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["guideGridId"] == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "guideGridId is required"
                    });
                }

                long gridIdLong = parameters["guideGridId"].ToObject<long>();
                var guideGridElement = doc.GetElement(new ElementId(gridIdLong));

                if (guideGridElement == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = $"Guide grid with ID {gridIdLong} not found"
                    });
                }

                string gridName = guideGridElement.Name;

                // Find all sheets using this guide grid
                var sheetsUsingGrid = new List<ViewSheet>();
                var allSheets = new FilteredElementCollector(doc)
                    .OfClass(typeof(ViewSheet))
                    .Cast<ViewSheet>()
                    .ToList();

                foreach (var sheet in allSheets)
                {
                    var param = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                    if (param != null && param.HasValue)
                    {
                        var assignedGridId = param.AsElementId();
                        if (assignedGridId != null && assignedGridId.Value == gridIdLong)
                        {
                            sheetsUsingGrid.Add(sheet);
                        }
                    }
                }

                using (var trans = new Transaction(doc, "Delete Guide Grid"))
                {
                    trans.Start();

                    // First remove from all sheets
                    foreach (var sheet in sheetsUsingGrid)
                    {
                        var param = sheet.get_Parameter(BuiltInParameter.SHEET_GUIDE_GRID);
                        if (param != null)
                        {
                            param.Set(ElementId.InvalidElementId);
                        }
                    }

                    // Then delete the guide grid element
                    doc.Delete(new ElementId(gridIdLong));

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    deletedGridId = gridIdLong,
                    deletedGridName = gridName,
                    sheetsAffected = sheetsUsingGrid.Count,
                    affectedSheets = sheetsUsingGrid.Select(s => s.SheetNumber).ToList(),
                    message = $"Deleted guide grid '{gridName}' (was on {sheetsUsingGrid.Count} sheets)"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Returns information about the standard 5x4 detail sheet grid layout
        /// Note: Guide grids must be created manually in Revit - this returns specifications only
        /// </summary>
        [MCPMethod("getStandardDetailGridSpec", Category = "SheetPattern")]
        public static string GetStandardDetailGridSpec(UIApplication uiApp, JObject parameters)
        {
            try
            {
                // Standard grid specification (from user):
                // - 5 columns x 4 rows = 20 cells
                // - Sheet boundaries: MinX=0.13', MaxX=2.70', MinY=0.10', MaxY=1.95'
                // - Full usable area: 2.57' x 1.85'
                // - Cell size: ~6.2" x 5.6" (0.517' x 0.463')

                double usableWidth = 2.70 - 0.13;  // 2.57'
                double usableHeight = 1.95 - 0.10; // 1.85'

                int columns = 5;
                int rows = 4;

                double cellWidth = usableWidth / columns;   // ~0.514'
                double cellHeight = usableHeight / rows;    // ~0.463'

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    gridName = "Standard Detail Grid 5x4",
                    columns = columns,
                    rows = rows,
                    totalCells = columns * rows,
                    sheetBounds = new
                    {
                        minX = 0.13,
                        maxX = 2.70,
                        minY = 0.10,
                        maxY = 1.95
                    },
                    usableArea = new
                    {
                        width = usableWidth,
                        height = usableHeight,
                        widthInches = usableWidth * 12,
                        heightInches = usableHeight * 12
                    },
                    cellSize = new
                    {
                        width = cellWidth,
                        height = cellHeight,
                        widthInches = cellWidth * 12,
                        heightInches = cellHeight * 12
                    },
                    note = "Guide grids must be created manually in Revit via View > Guide Grid. " +
                           "This specification shows the recommended grid layout for detail sheets.",
                    instructions = new[]
                    {
                        "1. Open a sheet in Revit",
                        "2. Go to View tab > Sheet Composition > Guide Grid",
                        "3. Create a new guide grid named 'Standard Detail Grid 5x4'",
                        $"4. Set grid spacing to approximately {cellHeight * 12:F1}\" (5.6 inches)",
                        "5. Use applyGuideGridToSheet to assign it to other sheets"
                    }
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Gets comprehensive grid cell data including all cell centers and boundaries.
        /// This encodes the complete grid knowledge for intelligent viewport placement.
        /// Grid Layout: 5 columns x 4 rows = 20 cells, numbered left-to-right, top-to-bottom
        /// </summary>
        [MCPMethod("getDetailGridCells", Category = "SheetPattern")]
        public static string GetDetailGridCells(UIApplication uiApp, JObject parameters)
        {
            try
            {
                // Grid specifications (learned from user testing)
                double minX = 0.13;
                double maxX = 2.70;
                double minY = 0.10;
                double maxY = 1.95;

                int columns = 5;
                int rows = 4;

                double usableWidth = maxX - minX;  // 2.57'
                double usableHeight = maxY - minY; // 1.85'
                double cellWidth = usableWidth / columns;   // ~0.514'
                double cellHeight = usableHeight / rows;    // ~0.463'

                // Calculate all cell centers
                // Numbering: Row 1 (top) = cells 1-5, Row 2 = cells 6-10, etc.
                // Y coordinates: Row 1 is at TOP (highest Y), Row 4 at BOTTOM (lowest Y)
                var cells = new List<object>();
                double[] rowYCenters = new double[rows];
                double[] colXCenters = new double[columns];

                // Calculate row Y centers (top to bottom)
                for (int r = 0; r < rows; r++)
                {
                    // Row 0 (top) has highest Y, Row 3 (bottom) has lowest Y
                    rowYCenters[r] = maxY - (r + 0.5) * cellHeight;
                }

                // Calculate column X centers (left to right)
                for (int c = 0; c < columns; c++)
                {
                    colXCenters[c] = minX + (c + 0.5) * cellWidth;
                }

                // Generate all 20 cells
                int cellNumber = 1;
                for (int r = 0; r < rows; r++)
                {
                    for (int c = 0; c < columns; c++)
                    {
                        cells.Add(new
                        {
                            cellNumber = cellNumber,
                            row = r + 1,
                            column = c + 1,
                            centerX = Math.Round(colXCenters[c], 4),
                            centerY = Math.Round(rowYCenters[r], 4),
                            bounds = new
                            {
                                minX = Math.Round(minX + c * cellWidth, 4),
                                maxX = Math.Round(minX + (c + 1) * cellWidth, 4),
                                minY = Math.Round(maxY - (r + 1) * cellHeight, 4),
                                maxY = Math.Round(maxY - r * cellHeight, 4)
                            }
                        });
                        cellNumber++;
                    }
                }

                // Calculate column boundaries (for 2-cell horizontal views)
                var columnBoundaries = new List<object>();
                for (int c = 0; c < columns - 1; c++)
                {
                    double boundaryX = (colXCenters[c] + colXCenters[c + 1]) / 2.0;
                    columnBoundaries.Add(new
                    {
                        betweenColumns = new[] { c + 1, c + 2 },
                        x = Math.Round(boundaryX, 4),
                        description = $"Boundary between columns {c + 1} and {c + 2}"
                    });
                }

                // Calculate row boundaries (for 2-cell vertical views)
                var rowBoundaries = new List<object>();
                for (int r = 0; r < rows - 1; r++)
                {
                    double boundaryY = (rowYCenters[r] + rowYCenters[r + 1]) / 2.0;
                    rowBoundaries.Add(new
                    {
                        betweenRows = new[] { r + 1, r + 2 },
                        y = Math.Round(boundaryY, 4),
                        description = $"Boundary between rows {r + 1} and {r + 2}"
                    });
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    grid = new
                    {
                        name = "Standard Detail Grid 5x4",
                        columns = columns,
                        rows = rows,
                        totalCells = columns * rows,
                        cellWidthFeet = Math.Round(cellWidth, 4),
                        cellHeightFeet = Math.Round(cellHeight, 4),
                        cellWidthInches = Math.Round(cellWidth * 12, 2),
                        cellHeightInches = Math.Round(cellHeight * 12, 2)
                    },
                    bounds = new
                    {
                        minX = minX,
                        maxX = maxX,
                        minY = minY,
                        maxY = maxY
                    },
                    cells = cells,
                    columnBoundaries = columnBoundaries,
                    rowBoundaries = rowBoundaries,
                    placementRules = new
                    {
                        singleCell = "Center view at cell center coordinates",
                        twoCellHorizontal = "Center view at column boundary X coordinate",
                        twoCellVertical = "Center view at row boundary Y coordinate",
                        fourCell = "Center view at intersection of column and row boundaries",
                        sizeThresholds = new
                        {
                            singleCellMaxWidth = Math.Round(cellWidth * 12, 2),
                            twoCellMaxWidth = Math.Round(cellWidth * 2 * 12, 2),
                            note = "Views wider than cell width should span 2 cells"
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Calculates how many grid cells a view needs based on its dimensions.
        /// Returns cell count and recommended placement strategy.
        /// </summary>
        [MCPMethod("calculateViewCellRequirements", Category = "SheetPattern")]
        public static string CalculateViewCellRequirements(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["viewId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "viewId is required" });

                var viewId = new ElementId(int.Parse(parameters["viewId"].ToString()));
                var view = doc.GetElement(viewId) as View;

                if (view == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "View not found" });

                // Get view dimensions
                double viewWidth = 0, viewHeight = 0;

                if (view is ViewDrafting)
                {
                    var outline = view.Outline;
                    if (outline != null)
                    {
                        viewWidth = outline.Max.U - outline.Min.U;
                        viewHeight = outline.Max.V - outline.Min.V;
                    }
                }
                else if (view.CropBoxActive)
                {
                    var cropBox = view.CropBox;
                    viewWidth = (cropBox.Max.X - cropBox.Min.X) / view.Scale;
                    viewHeight = (cropBox.Max.Y - cropBox.Min.Y) / view.Scale;
                }

                // Grid cell size
                double cellWidth = 0.514;  // ~6.17 inches
                double cellHeight = 0.463; // ~5.55 inches

                // Calculate cells needed
                int columnsNeeded = Math.Max(1, (int)Math.Ceiling(viewWidth / cellWidth));
                int rowsNeeded = Math.Max(1, (int)Math.Ceiling(viewHeight / cellHeight));
                int totalCells = columnsNeeded * rowsNeeded;

                // Determine placement strategy
                string strategy;
                string placementType;

                if (columnsNeeded == 1 && rowsNeeded == 1)
                {
                    strategy = "CENTER_AT_CELL";
                    placementType = "single-cell";
                }
                else if (columnsNeeded == 2 && rowsNeeded == 1)
                {
                    strategy = "CENTER_AT_COLUMN_BOUNDARY";
                    placementType = "2-cell-horizontal";
                }
                else if (columnsNeeded == 1 && rowsNeeded == 2)
                {
                    strategy = "CENTER_AT_ROW_BOUNDARY";
                    placementType = "2-cell-vertical";
                }
                else if (columnsNeeded == 2 && rowsNeeded == 2)
                {
                    strategy = "CENTER_AT_INTERSECTION";
                    placementType = "4-cell";
                }
                else
                {
                    strategy = "MANUAL_PLACEMENT";
                    placementType = $"{columnsNeeded}x{rowsNeeded}-cell";
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    viewId = (int)viewId.Value,
                    viewName = view.Name,
                    dimensions = new
                    {
                        widthFeet = Math.Round(viewWidth, 4),
                        heightFeet = Math.Round(viewHeight, 4),
                        widthInches = Math.Round(viewWidth * 12, 2),
                        heightInches = Math.Round(viewHeight * 12, 2)
                    },
                    cellRequirements = new
                    {
                        columnsNeeded = columnsNeeded,
                        rowsNeeded = rowsNeeded,
                        totalCells = totalCells,
                        placementType = placementType,
                        strategy = strategy
                    },
                    recommendation = strategy == "CENTER_AT_CELL"
                        ? "Place at any single cell center"
                        : strategy == "CENTER_AT_COLUMN_BOUNDARY"
                            ? "Place at column boundary (X = midpoint between two column centers)"
                            : strategy == "CENTER_AT_ROW_BOUNDARY"
                                ? "Place at row boundary (Y = midpoint between two row centers)"
                                : strategy == "CENTER_AT_INTERSECTION"
                                    ? "Place at intersection of column and row boundaries"
                                    : "View is larger than 4 cells - consider manual placement or scale adjustment"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Gets the next available grid cell on a sheet, accounting for already-placed viewports.
        /// Returns cell number and coordinates for sequential placement.
        /// </summary>
        [MCPMethod("getNextAvailableGridCell", Category = "SheetPattern")]
        public static string GetNextAvailableGridCell(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                if (parameters["sheetId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "sheetId is required" });

                var sheetId = new ElementId(int.Parse(parameters["sheetId"].ToString()));
                var sheet = doc.GetElement(sheetId) as ViewSheet;

                if (sheet == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "Sheet not found" });

                // Grid specifications
                double minX = 0.13, maxX = 2.70, minY = 0.10, maxY = 1.95;
                int columns = 5, rows = 4;
                double cellWidth = (maxX - minX) / columns;
                double cellHeight = (maxY - minY) / rows;

                // Calculate cell centers
                double[] colXCenters = new double[columns];
                double[] rowYCenters = new double[rows];

                for (int c = 0; c < columns; c++)
                    colXCenters[c] = minX + (c + 0.5) * cellWidth;
                for (int r = 0; r < rows; r++)
                    rowYCenters[r] = maxY - (r + 0.5) * cellHeight;

                // Track occupied cells
                bool[,] occupied = new bool[rows, columns];

                // Get existing viewports and mark occupied cells
                var viewportIds = sheet.GetAllViewports();
                foreach (ElementId vpId in viewportIds)
                {
                    var viewport = doc.GetElement(vpId) as Viewport;
                    if (viewport != null)
                    {
                        var center = viewport.GetBoxCenter();

                        // Find which cell(s) this viewport occupies
                        var bbox = viewport.GetBoxOutline();
                        double vpMinX = bbox.MinimumPoint.X;
                        double vpMaxX = bbox.MaximumPoint.X;
                        double vpMinY = bbox.MinimumPoint.Y;
                        double vpMaxY = bbox.MaximumPoint.Y;

                        // Mark all cells that this viewport overlaps
                        for (int r = 0; r < rows; r++)
                        {
                            for (int c = 0; c < columns; c++)
                            {
                                double cellMinX = minX + c * cellWidth;
                                double cellMaxX = minX + (c + 1) * cellWidth;
                                double cellMinY = maxY - (r + 1) * cellHeight;
                                double cellMaxY = maxY - r * cellHeight;

                                // Check if viewport overlaps this cell
                                if (vpMaxX > cellMinX && vpMinX < cellMaxX &&
                                    vpMaxY > cellMinY && vpMinY < cellMaxY)
                                {
                                    occupied[r, c] = true;
                                }
                            }
                        }
                    }
                }

                // Find first available cell (left-to-right, top-to-bottom)
                int nextCell = -1;
                int nextRow = -1, nextCol = -1;
                double nextX = 0, nextY = 0;

                for (int r = 0; r < rows && nextCell == -1; r++)
                {
                    for (int c = 0; c < columns && nextCell == -1; c++)
                    {
                        if (!occupied[r, c])
                        {
                            nextCell = r * columns + c + 1;
                            nextRow = r + 1;
                            nextCol = c + 1;
                            nextX = colXCenters[c];
                            nextY = rowYCenters[r];
                        }
                    }
                }

                // Count available cells
                int availableCount = 0;
                var availableCells = new List<int>();
                for (int r = 0; r < rows; r++)
                {
                    for (int c = 0; c < columns; c++)
                    {
                        if (!occupied[r, c])
                        {
                            availableCount++;
                            availableCells.Add(r * columns + c + 1);
                        }
                    }
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    sheetId = (int)sheetId.Value,
                    sheetNumber = sheet.SheetNumber,
                    existingViewports = viewportIds.Count,
                    nextAvailable = nextCell > 0 ? new
                    {
                        cellNumber = nextCell,
                        row = nextRow,
                        column = nextCol,
                        centerX = Math.Round(nextX, 4),
                        centerY = Math.Round(nextY, 4)
                    } : null,
                    availableCells = availableCells,
                    availableCount = availableCount,
                    isFull = nextCell == -1
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Places a view on a sheet at a specific grid cell, with automatic multi-cell handling.
        /// Supports single-cell, 2-cell horizontal, 2-cell vertical, and 4-cell placements.
        /// </summary>
        [MCPMethod("placeViewOnGridCell", Category = "SheetPattern")]
        public static string PlaceViewOnGridCell(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var uiDoc = uiApp.ActiveUIDocument;
                var doc = uiDoc.Document;

                if (parameters["sheetId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "sheetId is required" });
                if (parameters["viewId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "viewId is required" });
                if (parameters["cellNumber"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "cellNumber is required (1-20)" });

                var sheetId = new ElementId(int.Parse(parameters["sheetId"].ToString()));
                var viewId = new ElementId(int.Parse(parameters["viewId"].ToString()));
                int cellNumber = int.Parse(parameters["cellNumber"].ToString());

                // Optional: span multiple cells
                int columnsToSpan = parameters["columnsToSpan"]?.Value<int>() ?? 1;
                int rowsToSpan = parameters["rowsToSpan"]?.Value<int>() ?? 1;
                bool autoDetectSize = parameters["autoDetectSize"]?.Value<bool>() ?? true;

                var sheet = doc.GetElement(sheetId) as ViewSheet;
                var view = doc.GetElement(viewId) as View;

                if (sheet == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "Sheet not found" });
                if (view == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "View not found" });
                if (cellNumber < 1 || cellNumber > 20)
                    return JsonConvert.SerializeObject(new { success = false, error = "cellNumber must be 1-20" });

                // Grid specifications
                double minX = 0.13, maxX = 2.70, minY = 0.10, maxY = 1.95;
                int columns = 5, rows = 4;
                double cellWidth = (maxX - minX) / columns;
                double cellHeight = (maxY - minY) / rows;

                // Calculate cell row/column from cell number
                int cellRow = (cellNumber - 1) / columns;  // 0-based
                int cellCol = (cellNumber - 1) % columns;  // 0-based

                // Auto-detect size if requested
                if (autoDetectSize)
                {
                    double viewWidth = 0, viewHeight = 0;

                    if (view is ViewDrafting)
                    {
                        var outline = view.Outline;
                        if (outline != null)
                        {
                            viewWidth = outline.Max.U - outline.Min.U;
                            viewHeight = outline.Max.V - outline.Min.V;
                        }
                    }
                    else if (view.CropBoxActive)
                    {
                        var cropBox = view.CropBox;
                        viewWidth = (cropBox.Max.X - cropBox.Min.X) / view.Scale;
                        viewHeight = (cropBox.Max.Y - cropBox.Min.Y) / view.Scale;
                    }

                    // Determine span needed
                    if (viewWidth > cellWidth * 1.1) columnsToSpan = 2;
                    if (viewHeight > cellHeight * 1.1) rowsToSpan = 2;
                }

                // Calculate placement position
                double targetX, targetY;
                string placementType;

                if (columnsToSpan == 1 && rowsToSpan == 1)
                {
                    // Single cell - center at cell center
                    targetX = minX + (cellCol + 0.5) * cellWidth;
                    targetY = maxY - (cellRow + 0.5) * cellHeight;
                    placementType = "single-cell";
                }
                else if (columnsToSpan == 2 && rowsToSpan == 1)
                {
                    // 2-cell horizontal - center at column boundary
                    targetX = minX + (cellCol + 1) * cellWidth;  // Right edge of first cell = boundary
                    targetY = maxY - (cellRow + 0.5) * cellHeight;
                    placementType = "2-cell-horizontal";
                }
                else if (columnsToSpan == 1 && rowsToSpan == 2)
                {
                    // 2-cell vertical - center at row boundary
                    targetX = minX + (cellCol + 0.5) * cellWidth;
                    targetY = maxY - (cellRow + 1) * cellHeight;  // Bottom edge of first cell = boundary
                    placementType = "2-cell-vertical";
                }
                else
                {
                    // 4-cell or larger - center at intersection
                    targetX = minX + (cellCol + 1) * cellWidth;
                    targetY = maxY - (cellRow + 1) * cellHeight;
                    placementType = "multi-cell";
                }

                // Check if view can be placed
                if (!Viewport.CanAddViewToSheet(doc, sheetId, viewId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "View cannot be placed on this sheet (may already be placed elsewhere)"
                    });
                }

                using (var trans = new Transaction(doc, "Place View on Grid Cell"))
                {
                    trans.Start();

                    // Create viewport at sheet center first
                    var viewport = Viewport.Create(doc, sheetId, viewId, new XYZ(1.5, 1.0, 0));

                    if (viewport == null)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "Failed to create viewport"
                        });
                    }

                    // Move to target position
                    viewport.SetBoxCenter(new XYZ(targetX, targetY, 0));

                    trans.CommitAndCheck();

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        viewportId = (int)viewport.Id.Value,
                        viewId = (int)viewId.Value,
                        viewName = view.Name,
                        sheetId = (int)sheetId.Value,
                        placement = new
                        {
                            cellNumber = cellNumber,
                            row = cellRow + 1,
                            column = cellCol + 1,
                            columnsSpanned = columnsToSpan,
                            rowsSpanned = rowsToSpan,
                            type = placementType,
                            centerX = Math.Round(targetX, 4),
                            centerY = Math.Round(targetY, 4)
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Places a legend view on the right side of a sheet (standard practice for keynotes, floor plan legends).
        /// Position is determined by existing content and legend height.
        /// </summary>
        [MCPMethod("placeLegendOnSheetRight", Category = "SheetPattern")]
        public static string PlaceLegendOnSheetRight(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var uiDoc = uiApp.ActiveUIDocument;
                var doc = uiDoc.Document;

                if (parameters["sheetId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "sheetId is required" });
                if (parameters["legendId"] == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "legendId is required" });

                var sheetId = new ElementId(int.Parse(parameters["sheetId"].ToString()));
                var legendId = new ElementId(int.Parse(parameters["legendId"].ToString()));

                var sheet = doc.GetElement(sheetId) as ViewSheet;
                var legend = doc.GetElement(legendId) as View;

                if (sheet == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "Sheet not found" });
                if (legend == null)
                    return JsonConvert.SerializeObject(new { success = false, error = "Legend not found" });

                // Check if it's actually a legend
                if (legend.ViewType != ViewType.Legend)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Specified view is not a legend",
                        viewType = legend.ViewType.ToString()
                    });
                }

                // Get legend dimensions
                double legendWidth = 0, legendHeight = 0;
                var outline = legend.Outline;
                if (outline != null)
                {
                    legendWidth = outline.Max.U - outline.Min.U;
                    legendHeight = outline.Max.V - outline.Min.V;
                }

                // Sheet right side coordinates (between grid and title block)
                // Grid ends at X=2.70, title block typically starts around X=2.85
                // Right margin area: X ≈ 2.5 to 2.7
                double rightMarginX = 2.55;  // Center of right margin area

                // Vertical position - start near top, stack down
                double topY = 1.8;  // Below header area
                double bottomY = 0.2;  // Above footer area

                // Find existing legend viewports on right side to avoid overlap
                double nextY = topY;
                var viewportIds = sheet.GetAllViewports();

                foreach (ElementId vpId in viewportIds)
                {
                    var vp = doc.GetElement(vpId) as Viewport;
                    if (vp != null)
                    {
                        var center = vp.GetBoxCenter();
                        // Check if viewport is on the right side (X > 2.4)
                        if (center.X > 2.4)
                        {
                            var bbox = vp.GetBoxOutline();
                            double vpBottom = bbox.MinimumPoint.Y;
                            // Position new legend below existing
                            if (vpBottom < nextY)
                            {
                                nextY = vpBottom - 0.1; // 1.2 inch gap
                            }
                        }
                    }
                }

                // Center the legend vertically at nextY - legendHeight/2
                double targetX = rightMarginX;
                double targetY = nextY - legendHeight / 2;

                // Ensure not too low
                if (targetY - legendHeight / 2 < bottomY)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "No room on right side for legend - too many legends already placed",
                        suggestion = "Remove some legends or use a different sheet"
                    });
                }

                // Check if legend can be placed
                if (!Viewport.CanAddViewToSheet(doc, sheetId, legendId))
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Legend cannot be placed on this sheet (may already be placed elsewhere)"
                    });
                }

                using (var trans = new Transaction(doc, "Place Legend on Right Side"))
                {
                    trans.Start();

                    var viewport = Viewport.Create(doc, sheetId, legendId, new XYZ(targetX, targetY, 0));

                    if (viewport == null)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "Failed to create viewport for legend"
                        });
                    }

                    trans.CommitAndCheck();

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        viewportId = (int)viewport.Id.Value,
                        legendId = (int)legendId.Value,
                        legendName = legend.Name,
                        sheetId = (int)sheetId.Value,
                        placement = new
                        {
                            position = "right-side",
                            centerX = Math.Round(targetX, 4),
                            centerY = Math.Round(targetY, 4),
                            legendWidth = Math.Round(legendWidth * 12, 2),
                            legendHeight = Math.Round(legendHeight * 12, 2)
                        },
                        note = "Legend placed on right side per office standard"
                    });
                }
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        #endregion
    }
}
