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

namespace RevitMCPBridge
{
    public static class DimensioningMethods
    {
        /// <summary>
        /// Create a linear dimension between two reference points
        /// </summary>
        [MCPMethod("createLinearDimension", Category = "Dimensioning")]
        public static string CreateLinearDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                // Parse reference element IDs
                var elementId1 = new ElementId(int.Parse(parameters["elementId1"].ToString()));
                var elementId2 = new ElementId(int.Parse(parameters["elementId2"].ToString()));

                var element1 = doc.GetElement(elementId1);
                var element2 = doc.GetElement(elementId2);

                if (element1 == null || element2 == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "One or both elements not found"
                    });
                }

                // Parse dimension line location (optional)
                XYZ dimLineLocation = null;
                if (parameters["dimLineLocation"] != null)
                {
                    var locArray = parameters["dimLineLocation"].ToObject<double[]>();
                    dimLineLocation = new XYZ(locArray[0], locArray[1], locArray[2]);
                }

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

                    // Create reference array
                    var refArray = new ReferenceArray();
                    refArray.Append(new Reference(element1));
                    refArray.Append(new Reference(element2));

                    // Create dimension line
                    Line dimLine;
                    if (dimLineLocation != null)
                    {
                        // Get element locations
                        var loc1 = GetElementLocation(element1);
                        var loc2 = GetElementLocation(element2);

                        if (loc1 != null && loc2 != null)
                        {
                            dimLine = Line.CreateBound(
                                new XYZ(loc1.X, loc1.Y, dimLineLocation.Z),
                                new XYZ(loc2.X, loc2.Y, dimLineLocation.Z)
                            );
                        }
                        else
                        {
                            trans.RollBack();
                            return JsonConvert.SerializeObject(new
                            {
                                success = false,
                                error = "Could not determine element locations"
                            });
                        }
                    }
                    else
                    {
                        // Use default location
                        var loc1 = GetElementLocation(element1);
                        var loc2 = GetElementLocation(element2);

                        if (loc1 == null || loc2 == null)
                        {
                            trans.RollBack();
                            return JsonConvert.SerializeObject(new
                            {
                                success = false,
                                error = "Could not determine element locations"
                            });
                        }

                        dimLine = Line.CreateBound(loc1, loc2);
                    }

                    // Create the dimension
                    var dimension = doc.Create.NewDimension(view, dimLine, refArray);

                    trans.CommitAndCheck();

                    Log.Information($"Created linear dimension in view {viewId.Value}");

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        dimensionId = dimension.Id.Value,
                        viewId = viewId.Value
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating linear dimension");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Create an aligned dimension (follows element geometry)
        /// </summary>
        [MCPMethod("dimensionWallLength", Category = "Dimensioning",
            Description = "Dimension ONE wall's length: aligned dimension between the wall's two end faces, offset beside the wall. Params: wallId; viewId (optional, default active view); offsetFeet (optional, default 4).")]
        public static string DimensionWallLength(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument?.Document;
                if (doc == null) return JsonConvert.SerializeObject(new { success = false, error = "No active document" });
                if (parameters?["wallId"] == null) return JsonConvert.SerializeObject(new { success = false, error = "wallId is required" });

                var wall = doc.GetElement(new ElementId(int.Parse(parameters["wallId"].ToString()))) as Wall;
                if (wall == null) return JsonConvert.SerializeObject(new { success = false, error = "Wall not found" });

                View view = parameters["viewId"] != null
                    ? doc.GetElement(new ElementId(int.Parse(parameters["viewId"].ToString()))) as View
                    : doc.ActiveView;
                if (view == null) return JsonConvert.SerializeObject(new { success = false, error = "View not found" });

                var line = (wall.Location as LocationCurve)?.Curve as Line;
                if (line == null) return JsonConvert.SerializeObject(new { success = false, error = "Wall has no straight location line" });
                var dir = (line.GetEndPoint(1) - line.GetEndPoint(0)).Normalize();
                double offset = parameters["offsetFeet"]?.ToObject<double>() ?? 4.0;

                // the wall's two END faces = planar faces whose normal is parallel to the wall direction
                var opts = new Options { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
                var endFaces = new List<PlanarFace>();
                foreach (GeometryObject go in wall.get_Geometry(opts))
                    if (go is Solid solid)
                        foreach (Face f in solid.Faces)
                            if (f is PlanarFace pf && Math.Abs(pf.FaceNormal.DotProduct(dir)) > 0.99)
                                endFaces.Add(pf);
                if (endFaces.Count < 2)
                    return JsonConvert.SerializeObject(new { success = false, error = "Could not find the wall's end faces (joined ends?) — found " + endFaces.Count });
                var fStart = endFaces.OrderBy(f => f.Origin.DotProduct(dir)).First();
                var fEnd = endFaces.OrderByDescending(f => f.Origin.DotProduct(dir)).First();

                var perp = new XYZ(-dir.Y, dir.X, 0);
                var dimLine = Line.CreateBound(line.GetEndPoint(0) + perp * offset, line.GetEndPoint(1) + perp * offset);
                var refs = new ReferenceArray();
                refs.Append(fStart.Reference);
                refs.Append(fEnd.Reference);

                using (var trans = new Transaction(doc, "Dimension wall length"))
                {
                    trans.Start();
                    var fo = trans.GetFailureHandlingOptions();
                    try { fo.SetFailuresPreprocessor(new WarningSwallower()); trans.SetFailureHandlingOptions(fo); } catch { }
                    var dim = doc.Create.NewDimension(view, dimLine, refs);
                    trans.Commit();
                    return JsonConvert.SerializeObject(new
                    {
                        success = true, dimensionId = (int)dim.Id.Value, wallId = (int)wall.Id.Value,
                        value = dim.ValueString, message = "Dimensioned wall " + wall.Id.Value + " (" + dim.ValueString + ") in view '" + view.Name + "'."
                    });
                }
            }
            catch (Exception ex) { return JsonConvert.SerializeObject(new { success = false, error = ex.Message }); }
        }

        [MCPMethod("createAlignedDimension", Category = "Dimensioning")]
        public static string CreateAlignedDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                // Parse reference points
                var point1Array = parameters["point1"].ToObject<double[]>();
                var point2Array = parameters["point2"].ToObject<double[]>();
                var offsetArray = parameters["offset"].ToObject<double[]>();

                var point1 = new XYZ(point1Array[0], point1Array[1], point1Array[2]);
                var point2 = new XYZ(point2Array[0], point2Array[1], point2Array[2]);
                var offset = new XYZ(offsetArray[0], offsetArray[1], offsetArray[2]);

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

                    // Create line for dimension
                    var dimLine = Line.CreateBound(point1, point2);

                    // Offset the line
                    var transform = Transform.CreateTranslation(offset);
                    var offsetLine = dimLine.CreateTransformed(transform) as Line;

                    // Create reference array (using the original points)
                    var refArray = new ReferenceArray();

                    // For aligned dimensions, we typically need references from elements
                    // This is a simplified version - you may need to pass element references

                    trans.RollBack(); // Placeholder - needs proper references

                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Aligned dimension requires element references - use batch methods instead"
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating aligned dimension");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Batch dimension all walls in a view
        /// </summary>
        /// <summary>
        /// Batch dimension walls in a view with improved continuous string support
        /// Creates ONE dimension string per wall group (horizontal/vertical) instead of individual dimensions
        /// </summary>
        [MCPMethod("batchDimensionWalls", Category = "Dimensioning")]
        public static string BatchDimensionWalls(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                double offset = parameters["offset"]?.ToObject<double>() ?? 5.0; // Default 5 feet offset
                string direction = parameters["direction"]?.ToString()?.ToLower() ?? "both"; // horizontal, vertical, or both

                // Wall filtering parameters for tier control
                string wallType = parameters["wallType"]?.ToString()?.ToLower() ?? "all";
                double? minWidth = parameters["minWidth"]?.ToObject<double?>();
                double? maxWidth = parameters["maxWidth"]?.ToObject<double?>();

                // If true, dimension only to wall endpoints (ignore door/window openings)
                bool wallsOnly = parameters["wallsOnly"]?.ToObject<bool>() ?? false;

                // Get all walls in view
                var allWalls = new FilteredElementCollector(doc, view.Id)
                    .OfCategory(BuiltInCategory.OST_Walls)
                    .WhereElementIsNotElementType()
                    .Cast<Wall>()
                    .ToList();

                // Filter walls based on type and dimensions
                var walls = allWalls.Where(w =>
                {
                    try
                    {
                        // Filter by wall type (structural vs partition)
                        if (wallType != "all")
                        {
                            var wallTypeObj = doc.GetElement(w.GetTypeId()) as WallType;
                            if (wallTypeObj != null)
                            {
                                var function = wallTypeObj.Function;

                                if (wallType == "structural")
                                {
                                    if (function != WallFunction.Exterior)
                                    {
                                        if (function == WallFunction.Interior)
                                        {
                                            var widthParam = w.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
                                            if (widthParam != null)
                                            {
                                                double width = widthParam.AsDouble();
                                                if (width <= 0.5)
                                                {
                                                    return false;
                                                }
                                            }
                                            else
                                            {
                                                return false;
                                            }
                                        }
                                        else
                                        {
                                            return false;
                                        }
                                    }
                                }
                                else if (wallType == "partition")
                                {
                                    if (function != WallFunction.Interior)
                                    {
                                        return false;
                                    }

                                    var widthParam = w.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
                                    if (widthParam != null)
                                    {
                                        double width = widthParam.AsDouble();
                                        if (width > 0.5 && !minWidth.HasValue)
                                        {
                                            return false;
                                        }
                                    }
                                }
                                else if (wallType == "exterior")
                                {
                                    if (function != WallFunction.Exterior)
                                    {
                                        return false;
                                    }
                                }
                                else if (wallType == "interior")
                                {
                                    if (function != WallFunction.Interior)
                                    {
                                        return false;
                                    }
                                }
                            }
                        }

                        // Filter by wall width/thickness
                        if (minWidth.HasValue || maxWidth.HasValue)
                        {
                            double width = 0;

                            // Try to get width from WallType first (more reliable)
                            var wallTypeObj = doc.GetElement(w.GetTypeId()) as WallType;
                            if (wallTypeObj != null)
                            {
                                width = wallTypeObj.Width;
                            }
                            else
                            {
                                // Fallback to wall parameter
                                var widthParam = w.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM);
                                if (widthParam != null)
                                {
                                    width = widthParam.AsDouble();
                                }
                            }

                            if (width > 0)
                            {
                                if (minWidth.HasValue && width < minWidth.Value) return false;
                                if (maxWidth.HasValue && width > maxWidth.Value) return false;
                            }
                        }

                        return true;
                    }
                    catch
                    {
                        return true; // If filtering fails, include the wall
                    }
                }).ToList();

                Log.Information($"Filtered to {walls.Count} walls from {allWalls.Count} total in view {viewId.Value}");

                // Collinearity tolerance in feet (walls within this distance are considered collinear)
                double collinearityTolerance = parameters["collinearityTolerance"]?.ToObject<double>() ?? 1.0;

                // Group walls by direction AND collinearity (position along perpendicular axis)
                // Key format: "horizontal_Y123.45" or "vertical_X45.67" to group walls on the same line
                var wallGroups = new Dictionary<string, List<(Wall wall, Line curve, XYZ direction)>>();

                foreach (var wall in walls)
                {
                    try
                    {
                        var locationCurve = wall.Location as LocationCurve;
                        if (locationCurve == null) continue;

                        var curve = locationCurve.Curve as Line;
                        if (curve == null) continue;

                        // Calculate wall direction
                        var startPoint = curve.GetEndPoint(0);
                        var endPoint = curve.GetEndPoint(1);
                        var wallDir = (endPoint - startPoint).Normalize();

                        // Get wall midpoint for position grouping
                        var midY = (startPoint.Y + endPoint.Y) / 2;
                        var midX = (startPoint.X + endPoint.X) / 2;

                        // Determine if wall is horizontal or vertical
                        double angleThreshold = 0.1; // ~5 degrees
                        bool isHorizontal = Math.Abs(wallDir.Y) < angleThreshold;
                        bool isVertical = Math.Abs(wallDir.X) < angleThreshold;

                        string groupKey = null;
                        if (isHorizontal && (direction == "horizontal" || direction == "both"))
                        {
                            // For horizontal walls, group by Y position (rounded to tolerance)
                            double roundedY = Math.Round(midY / collinearityTolerance) * collinearityTolerance;
                            groupKey = $"horizontal_Y{roundedY:F2}";
                        }
                        else if (isVertical && (direction == "vertical" || direction == "both"))
                        {
                            // For vertical walls, group by X position (rounded to tolerance)
                            double roundedX = Math.Round(midX / collinearityTolerance) * collinearityTolerance;
                            groupKey = $"vertical_X{roundedX:F2}";
                        }

                        if (groupKey != null)
                        {
                            if (!wallGroups.ContainsKey(groupKey))
                            {
                                wallGroups[groupKey] = new List<(Wall, Line, XYZ)>();
                            }
                            wallGroups[groupKey].Add((wall, curve, wallDir));
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Warning($"Failed to group wall {wall.Id.Value}: {ex.Message}");
                    }
                }

                Log.Information($"Grouped walls into {wallGroups.Count} collinear groups: {string.Join(", ", wallGroups.Select(kvp => $"{kvp.Key}={kvp.Value.Count}"))}");

                var dimensionedCount = 0;
                var dimensionIds = new List<long>();
                var skippedWalls = new List<string>();

                using (var trans = new Transaction(doc, "Batch Dimension Walls"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    // Process each collinear group
                    foreach (var group in wallGroups)
                    {
                        try
                        {
                            var groupKey = group.Key;
                            var groupWalls = group.Value;

                            // Skip groups with only one wall (need at least 2 for meaningful dimension)
                            if (groupWalls.Count < 2)
                            {
                                Log.Information($"Skipping group {groupKey}: only {groupWalls.Count} wall(s)");
                                continue;
                            }

                            bool isHorizontalGroup = groupKey.StartsWith("horizontal");

                            // Sort walls by position along their axis
                            if (isHorizontalGroup)
                            {
                                // Horizontal walls: sort by X position (left to right)
                                groupWalls.Sort((a, b) =>
                                {
                                    var aMinX = Math.Min(a.curve.GetEndPoint(0).X, a.curve.GetEndPoint(1).X);
                                    var bMinX = Math.Min(b.curve.GetEndPoint(0).X, b.curve.GetEndPoint(1).X);
                                    return aMinX.CompareTo(bMinX);
                                });
                            }
                            else
                            {
                                // Vertical walls: sort by Y position (bottom to top)
                                groupWalls.Sort((a, b) =>
                                {
                                    var aMinY = Math.Min(a.curve.GetEndPoint(0).Y, a.curve.GetEndPoint(1).Y);
                                    var bMinY = Math.Min(b.curve.GetEndPoint(0).Y, b.curve.GetEndPoint(1).Y);
                                    return aMinY.CompareTo(bMinY);
                                });
                            }

                            // Build reference array for this collinear group
                            var refArray = new ReferenceArray();
                            var options = new Options { ComputeReferences = true, View = view };

                            foreach (var (wall, curve, wallDir) in groupWalls)
                            {
                                try
                                {
                                    var geomElem = wall.get_Geometry(options);
                                    if (geomElem == null) continue;

                                    // Get wall endpoints for filtering when wallsOnly is true
                                    var wallStart = curve.GetEndPoint(0);
                                    var wallEnd = curve.GetEndPoint(1);

                                    List<Reference> faceRefs = new List<Reference>();
                                    foreach (GeometryObject geomObj in geomElem)
                                    {
                                        if (geomObj is Solid solid)
                                        {
                                            foreach (Face face in solid.Faces)
                                            {
                                                if (face is PlanarFace planarFace)
                                                {
                                                    var faceNormal = planarFace.FaceNormal;
                                                    var dot = Math.Abs(faceNormal.DotProduct(wallDir));

                                                    if (dot > 0.9) // Nearly perpendicular to wall direction
                                                    {
                                                        if (wallsOnly)
                                                        {
                                                            // Only include faces at wall endpoints (not door/window jambs)
                                                            var bbox = face.GetBoundingBox();
                                                            var faceCenter = (bbox.Min + bbox.Max) / 2;
                                                            // Transform to model coordinates
                                                            var transform = planarFace.ComputeDerivatives(faceCenter).Origin;

                                                            // Check if face center is near wall start or end
                                                            double tolerance = 0.5; // 6 inches
                                                            bool nearStart = Math.Abs(transform.X - wallStart.X) < tolerance &&
                                                                           Math.Abs(transform.Y - wallStart.Y) < tolerance;
                                                            bool nearEnd = Math.Abs(transform.X - wallEnd.X) < tolerance &&
                                                                         Math.Abs(transform.Y - wallEnd.Y) < tolerance;

                                                            if (nearStart || nearEnd)
                                                            {
                                                                faceRefs.Add(face.Reference);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            // Include all perpendicular faces (original behavior)
                                                            faceRefs.Add(face.Reference);
                                                            if (faceRefs.Count >= 2) break;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        if (!wallsOnly && faceRefs.Count >= 2) break;
                                    }

                                    // Add face references to the array
                                    foreach (var faceRef in faceRefs)
                                    {
                                        refArray.Append(faceRef);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Log.Warning($"Failed to get references for wall {wall.Id.Value}: {ex.Message}");
                                }
                            }

                            if (refArray.Size < 2)
                            {
                                Log.Warning($"Group {groupKey} has insufficient references ({refArray.Size})");
                                continue;
                            }

                            // Calculate dimension line that spans this collinear group
                            var firstWall = groupWalls.First();
                            var lastWall = groupWalls.Last();

                            XYZ firstPoint, lastPoint;
                            if (isHorizontalGroup)
                            {
                                // Use leftmost point of first wall, rightmost of last
                                firstPoint = firstWall.curve.GetEndPoint(0).X < firstWall.curve.GetEndPoint(1).X
                                    ? firstWall.curve.GetEndPoint(0) : firstWall.curve.GetEndPoint(1);
                                lastPoint = lastWall.curve.GetEndPoint(0).X > lastWall.curve.GetEndPoint(1).X
                                    ? lastWall.curve.GetEndPoint(0) : lastWall.curve.GetEndPoint(1);
                            }
                            else
                            {
                                // Use bottom point of first wall, top of last
                                firstPoint = firstWall.curve.GetEndPoint(0).Y < firstWall.curve.GetEndPoint(1).Y
                                    ? firstWall.curve.GetEndPoint(0) : firstWall.curve.GetEndPoint(1);
                                lastPoint = lastWall.curve.GetEndPoint(0).Y > lastWall.curve.GetEndPoint(1).Y
                                    ? lastWall.curve.GetEndPoint(0) : lastWall.curve.GetEndPoint(1);
                            }

                            // Calculate offset direction (perpendicular to walls)
                            var avgDir = firstWall.direction;
                            var offsetDirection = new XYZ(-avgDir.Y, avgDir.X, 0);
                            var offsetVector = offsetDirection * offset;

                            // Create dimension line
                            var dimLineStart = firstPoint + offsetVector;
                            var dimLineEnd = lastPoint + offsetVector;
                            var dimLine = Line.CreateBound(dimLineStart, dimLineEnd);

                            // Create dimension for this collinear group
                            var dimension = doc.Create.NewDimension(view, dimLine, refArray);

                            if (dimension != null)
                            {
                                dimensionIds.Add(dimension.Id.Value);
                                dimensionedCount++;
                                Log.Information($"Created dimension for collinear group {groupKey} with {groupWalls.Count} walls, {refArray.Size} references");
                            }
                        }
                        catch (Exception ex)
                        {
                            Log.Error($"Failed to dimension group {group.Key}: {ex.Message}");
                            skippedWalls.Add($"Group {group.Key}: {ex.Message}");
                        }
                    }

                    trans.CommitAndCheck();
                }

                Log.Information($"Created {dimensionedCount} dimension strings for {walls.Count} walls in view {viewId.Value}");

                // Build message with filtering info
                string filterInfo = wallType != "all" ? $" ({wallType} walls only)" : "";
                if (minWidth.HasValue || maxWidth.HasValue)
                {
                    string widthInfo = "";
                    if (minWidth.HasValue && maxWidth.HasValue)
                        widthInfo = $", width {minWidth.Value}'-{maxWidth.Value}'";
                    else if (minWidth.HasValue)
                        widthInfo = $", min width {minWidth.Value}'";
                    else
                        widthInfo = $", max width {maxWidth.Value}'";
                    filterInfo += widthInfo;
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    totalWalls = allWalls.Count,
                    filteredWalls = walls.Count,
                    collinearGroups = wallGroups.Count,
                    dimensionStringsCreated = dimensionedCount,
                    dimensionIds = dimensionIds,
                    skippedWalls = skippedWalls,
                    viewId = viewId.Value,
                    wallType = wallType,
                    offset = offset,
                    direction = direction,
                    collinearityTolerance = collinearityTolerance,
                    wallsOnly = wallsOnly,
                    message = $"Created {dimensionedCount} dimension string(s) for {wallGroups.Count} collinear wall groups ({walls.Count} walls total){filterInfo}{(wallsOnly ? ", walls only (no doors/windows)" : "")} at {offset}' offset"
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error batch dimensioning walls");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        [MCPMethod("batchDimensionDoors", Category = "Dimensioning")]
        public static string BatchDimensionDoors(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                double offset = parameters["offset"]?.ToObject<double>() ?? 3.0; // Default 3 feet offset

                // Get all doors in view
                var doors = new FilteredElementCollector(doc, view.Id)
                    .OfCategory(BuiltInCategory.OST_Doors)
                    .WhereElementIsNotElementType()
                    .Cast<FamilyInstance>()
                    .ToList();

                var dimensionedCount = 0;
                var dimensionIds = new List<long>();
                var skippedDoors = new List<string>();

                using (var trans = new Transaction(doc, "Batch Dimension Doors"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    foreach (var door in doors)
                    {
                        try
                        {
                            // Get door location and orientation
                            var doorLocation = door.Location as LocationPoint;
                            if (doorLocation == null)
                            {
                                skippedDoors.Add($"Door {door.Id.Value}: No location point");
                                continue;
                            }

                            var doorPoint = doorLocation.Point;
                            var doorRotation = doorLocation.Rotation;

                            // Get door width from parameter
                            var widthParam = door.Symbol.get_Parameter(BuiltInParameter.DOOR_WIDTH);
                            if (widthParam == null)
                            {
                                skippedDoors.Add($"Door {door.Id.Value}: No width parameter");
                                continue;
                            }

                            double doorWidth = widthParam.AsDouble();

                            // Get wall the door is hosted in
                            var hostWall = door.Host as Wall;
                            if (hostWall == null)
                            {
                                skippedDoors.Add($"Door {door.Id.Value}: Not hosted in a wall");
                                continue;
                            }

                            // Get wall location curve to determine door orientation
                            var wallLocationCurve = hostWall.Location as LocationCurve;
                            if (wallLocationCurve == null)
                            {
                                skippedDoors.Add($"Door {door.Id.Value}: Host wall has no location curve");
                                continue;
                            }

                            var wallCurve = wallLocationCurve.Curve;
                            var wallDirection = (wallCurve.GetEndPoint(1) - wallCurve.GetEndPoint(0)).Normalize();

                            // Jambs are separated ALONG the wall run; the dimension line is
                            // offset perpendicular to the wall (into the room). The old code had
                            // both of these swapped, so the computed jamb points never landed
                            // near the actual opening.
                            var perpDirection = new XYZ(-wallDirection.Y, wallDirection.X, 0);
                            var halfWidth = doorWidth / 2.0;

                            // Dimension line: parallel to the wall, pulled off by `offset`, and
                            // extended just past both jambs so the witness lines land cleanly.
                            var lineCenter = doorPoint + (perpDirection * offset);
                            var dimLineStart = lineCenter - (wallDirection * (halfWidth + 1.0));
                            var dimLineEnd = lineCenter + (wallDirection * (halfWidth + 1.0));
                            var dimLine = Line.CreateBound(dimLineStart, dimLineEnd);

                            // Preferred path: ask the door family for its own jamb references.
                            // FamilyInstanceReferenceType.Left/Right are exactly the reference
                            // planes Revit itself dimensions a door opening to.
                            var jambRefs = new List<Reference>();
                            Reference leftRef = door.GetReferences(FamilyInstanceReferenceType.Left)?.FirstOrDefault();
                            Reference rightRef = door.GetReferences(FamilyInstanceReferenceType.Right)?.FirstOrDefault();

                            if (leftRef != null && rightRef != null)
                            {
                                jambRefs.Add(leftRef);
                                jambRefs.Add(rightRef);
                            }
                            else
                            {
                                // Fallback: derive jamb references from the host wall solid.
                                // Match by HORIZONTAL (XY) distance only and only against VERTICAL
                                // edges. The old bug compared a floor-level jamb point against each
                                // edge's 3D midpoint, which sits at mid-wall height (~4 ft up) — so
                                // the distance check could never pass for a door of any width.
                                var leftJambXY = doorPoint - (wallDirection * halfWidth);
                                var rightJambXY = doorPoint + (wallDirection * halfWidth);
                                var options = new Options { ComputeReferences = true, View = view };
                                var wallGeom = hostWall.get_Geometry(options);
                                if (wallGeom != null)
                                {
                                    Reference foundLeft = null, foundRight = null;
                                    foreach (GeometryObject geomObj in wallGeom)
                                    {
                                        if (!(geomObj is Solid solid)) continue;
                                        foreach (Edge edge in solid.Edges)
                                        {
                                            var curve = edge.AsCurve();
                                            if (curve == null) continue;

                                            var span = curve.GetEndPoint(1) - curve.GetEndPoint(0);
                                            if (span.GetLength() < 1e-6) continue;
                                            // Only the vertical jamb returns, not horizontal edges.
                                            if (Math.Abs(span.Normalize().Z) < 0.9) continue;

                                            var p = curve.GetEndPoint(0);
                                            var pXY = new XYZ(p.X, p.Y, 0);
                                            if (foundLeft == null &&
                                                pXY.DistanceTo(new XYZ(leftJambXY.X, leftJambXY.Y, 0)) < 0.25)
                                            {
                                                foundLeft = edge.Reference;
                                            }
                                            else if (foundRight == null &&
                                                     pXY.DistanceTo(new XYZ(rightJambXY.X, rightJambXY.Y, 0)) < 0.25)
                                            {
                                                foundRight = edge.Reference;
                                            }

                                            if (foundLeft != null && foundRight != null) break;
                                        }
                                        if (foundLeft != null && foundRight != null) break;
                                    }
                                    if (foundLeft != null && foundRight != null)
                                    {
                                        jambRefs.Add(foundLeft);
                                        jambRefs.Add(foundRight);
                                    }
                                }
                            }

                            if (jambRefs.Count >= 2)
                            {
                                var refArray = new ReferenceArray();
                                refArray.Append(jambRefs[0]);
                                refArray.Append(jambRefs[1]);

                                var dimension = doc.Create.NewDimension(view, dimLine, refArray);
                                if (dimension != null)
                                {
                                    dimensionIds.Add(dimension.Id.Value);
                                    dimensionedCount++;
                                }
                                else
                                {
                                    skippedDoors.Add($"Door {door.Id.Value}: NewDimension returned null (width: {doorWidth})");
                                }
                            }
                            else
                            {
                                skippedDoors.Add($"Door {door.Id.Value}: no jamb references available — family exposes neither Left/Right refs nor matchable wall jamb edges (width: {doorWidth})");
                            }
                        }
                        catch (Exception ex)
                        {
                            skippedDoors.Add($"Door {door.Id.Value}: {ex.Message}");
                            Log.Warning($"Failed to dimension door {door.Id.Value}: {ex.Message}");
                        }
                    }

                    trans.CommitAndCheck();
                }

                Log.Information($"Dimensioned {dimensionedCount} of {doors.Count} doors in view {viewId.Value}");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    totalDoors = doors.Count,
                    dimensionedCount = dimensionedCount,
                    dimensionIds = dimensionIds,
                    skippedDoors = skippedDoors,
                    viewId = viewId.Value,
                    message = $"Successfully dimensioned {dimensionedCount} door openings"
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error batch dimensioning doors");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Get all dimensions in a view
        /// </summary>
        [MCPMethod("getDimensionsInView", Category = "Dimensioning")]
        public static string GetDimensionsInView(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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 all dimensions in view
                var dimensions = new FilteredElementCollector(doc, view.Id)
                    .OfClass(typeof(Dimension))
                    .Cast<Dimension>()
                    .ToList();

                var dimensionList = new List<object>();

                foreach (var dim in dimensions)
                {
                    try
                    {
                        dimensionList.Add(new
                        {
                            dimensionId = dim.Id.Value,
                            value = dim.Value,
                            valueString = dim.ValueString,
                            dimensionType = dim.DimensionType?.Name,
                            curve = dim.Curve != null ? "Has curve" : "No curve",
                            numberOfSegments = dim.Segments?.Size ?? 0
                        });
                    }
                    catch
                    {
                        // Skip dimensions that can't be processed
                    }
                }

                Log.Information($"Found {dimensionList.Count} dimensions in view {viewId.Value}");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    viewId = viewId.Value,
                    dimensionCount = dimensionList.Count,
                    dimensions = dimensionList
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error getting dimensions in view");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Delete a dimension by ID
        /// </summary>
        [MCPMethod("deleteDimension", Category = "Dimensioning")]
        public static string DeleteDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));

                var dimension = doc.GetElement(dimensionId);

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

                using (var trans = new Transaction(doc, "Delete Dimension"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    doc.Delete(dimensionId);
                    trans.CommitAndCheck();
                }

                Log.Information($"Deleted dimension {dimensionId.Value}");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    deletedDimensionId = dimensionId.Value
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error deleting dimension");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Helper method to get element location
        /// </summary>
        private static XYZ GetElementLocation(Element element)
        {
            if (element.Location is LocationPoint locPoint)
            {
                return locPoint.Point;
            }
            else if (element.Location is LocationCurve locCurve)
            {
                return locCurve.Curve.Evaluate(0.5, true);
            }
            else
            {
                // Use bounding box center as fallback
                var bbox = element.get_BoundingBox(null);
                if (bbox != null)
                {
                    return (bbox.Min + bbox.Max) / 2;
                }
            }
            return null;
        }

        /// <summary>
        /// PHASE 1B: Get window center reference for dimensioning
        /// </summary>
        private static Reference GetWindowCenterReference(Document doc, Element window, View view)
        {
            try
            {
                // Try to get location point first (most accurate for windows)
                if (window.Location is LocationPoint locPoint)
                {
                    return new Reference(window);
                }

                // Fallback: Use bounding box center
                var bbox = window.get_BoundingBox(view);
                if (bbox == null)
                {
                    bbox = window.get_BoundingBox(null);
                }

                if (bbox != null)
                {
                    // Calculate center point
                    XYZ center = (bbox.Min + bbox.Max) / 2;

                    // For windows, we can use the element's own reference
                    // The Revit API will snap to the center for family instances
                    return new Reference(window);
                }

                Log.Warning($"Could not calculate center for window {window.Id}");
                return null;
            }
            catch (Exception ex)
            {
                Log.Error($"Error getting window center reference: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// PHASE 1B: Get door center reference for dimensioning
        /// </summary>
        private static Reference GetDoorCenterReference(Document doc, Element door, View view)
        {
            try
            {
                // Try to get location point first (most accurate for doors)
                if (door.Location is LocationPoint locPoint)
                {
                    return new Reference(door);
                }

                // Fallback: Use bounding box center
                var bbox = door.get_BoundingBox(view);
                if (bbox == null)
                {
                    bbox = door.get_BoundingBox(null);
                }

                if (bbox != null)
                {
                    // Calculate center point
                    XYZ center = (bbox.Min + bbox.Max) / 2;

                    // For doors, we can use the element's own reference
                    // The Revit API will snap to the center for family instances
                    return new Reference(door);
                }

                Log.Warning($"Could not calculate center for door {door.Id}");
                return null;
            }
            catch (Exception ex)
            {
                Log.Error($"Error getting door center reference: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// PHASE 1B: Calculate dimension line for custom dimension string
        /// </summary>
        private static Line CalculateDimensionLine(
            Document doc,
            View view,
            ReferenceArray references,
            double offset,
            string direction)
        {
            try
            {
                if (references.Size < 2)
                {
                    throw new ArgumentException("Need at least 2 references to create dimension line");
                }

                // Get points from first and last references
                var firstRef = references.get_Item(0);
                var lastRef = references.get_Item(references.Size - 1);

                // Get the elements
                var firstElem = doc.GetElement(firstRef);
                var lastElem = doc.GetElement(lastRef);

                // Get center points
                var firstPoint = GetElementLocation(firstElem);
                var lastPoint = GetElementLocation(lastElem);

                if (firstPoint == null || lastPoint == null)
                {
                    throw new InvalidOperationException("Could not get element locations");
                }

                // Calculate dimension line based on direction
                XYZ p1, p2;

                if (direction.ToLower() == "horizontal")
                {
                    // Offset in Y direction (perpendicular to X axis)
                    p1 = new XYZ(firstPoint.X, firstPoint.Y + offset, firstPoint.Z);
                    p2 = new XYZ(lastPoint.X, lastPoint.Y + offset, lastPoint.Z);
                }
                else if (direction.ToLower() == "vertical")
                {
                    // Offset in X direction (perpendicular to Y axis)
                    p1 = new XYZ(firstPoint.X + offset, firstPoint.Y, firstPoint.Z);
                    p2 = new XYZ(lastPoint.X + offset, lastPoint.Y, lastPoint.Z);
                }
                else
                {
                    throw new ArgumentException($"Invalid direction: {direction}. Use 'horizontal' or 'vertical'");
                }

                return Line.CreateBound(p1, p2);
            }
            catch (Exception ex)
            {
                Log.Error($"Error calculating dimension line: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// PHASE 1B: Create custom dimension string with specified reference points
        /// Enables Tier 2 dimensioning with window/door centers
        /// </summary>
        [MCPMethod("createDimensionString", Category = "Dimensioning")]
        public static string CreateDimensionString(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                // Parse reference points array
                var refPointsArray = parameters["referencePoints"] as JArray;
                if (refPointsArray == null || refPointsArray.Count < 2)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Need at least 2 reference points to create dimension"
                    });
                }

                double offset = parameters["offset"]?.ToObject<double>() ?? 5.0;
                string direction = parameters["direction"]?.ToString()?.ToLower() ?? "horizontal";

                // Build reference array
                var references = new ReferenceArray();
                var refTypeCounts = new Dictionary<string, int>();

                using (Transaction trans = new Transaction(doc, "Create Custom Dimension String"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    foreach (JObject refPoint in refPointsArray)
                    {
                        string refType = refPoint["type"]?.ToString()?.ToLower();
                        int elementId = int.Parse(refPoint["elementId"].ToString());

                        var element = doc.GetElement(new ElementId(elementId));
                        if (element == null)
                        {
                            Log.Warning($"Element {elementId} not found, skipping");
                            continue;
                        }

                        Reference reference = null;

                        switch (refType)
                        {
                            case "wall_face":
                                // Get wall face reference (falls back to the wall
                                // centerline reference only if no face is found)
                                var wall = element as Wall;
                                if (wall != null)
                                {
                                    string side = refPoint["side"]?.ToString()?.ToLower() ?? "exterior";
                                    reference = GetWallFaceReferenceForDimension(
                                        wall,
                                        new Options { ComputeReferences = true, View = view },
                                        side == "exterior");
                                }
                                break;

                            case "grid":
                                // Get grid reference
                                var grid = element as Grid;
                                if (grid != null)
                                {
                                    // For grids, we create a reference to the grid curve
                                    reference = new Reference(grid);
                                }
                                break;

                            case "window_center":
                                reference = GetWindowCenterReference(doc, element, view);
                                break;

                            case "door_center":
                                reference = GetDoorCenterReference(doc, element, view);
                                break;

                            default:
                                Log.Warning($"Unknown reference type: {refType}");
                                continue;
                        }

                        if (reference != null)
                        {
                            references.Append(reference);

                            // Track reference type counts
                            if (!refTypeCounts.ContainsKey(refType))
                            {
                                refTypeCounts[refType] = 0;
                            }
                            refTypeCounts[refType]++;
                        }
                    }

                    // Check if we have enough references
                    if (references.Size < 2)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "Could not create enough valid references. Need at least 2."
                        });
                    }

                    // Calculate dimension line
                    Line dimLine = CalculateDimensionLine(doc, view, references, offset, direction);

                    // Create dimension
                    Dimension dimension = doc.Create.NewDimension(view, dimLine, references);

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

                    trans.CommitAndCheck();

                    // Build success message
                    var refTypesList = string.Join(", ", refTypeCounts.Select(kvp => $"{kvp.Value} {kvp.Key}"));

                    Log.Information($"Created custom dimension string with {references.Size} references: {refTypesList}");

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        dimensionId = dimension.Id.Value,
                        referenceCount = references.Size,
                        referenceTypes = refTypeCounts,
                        offset = offset,
                        direction = direction,
                        message = $"Created dimension string with {references.Size} reference points ({refTypesList})"
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Error creating custom dimension string: {ex.Message}");
                Log.Error($"Stack trace: {ex.StackTrace}");

                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Batch dimension grids - creates continuous dimension strings for grids
        /// </summary>
        [MCPMethod("batchDimensionGrids", Category = "Dimensioning")]
        public static string BatchDimensionGrids(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse parameters
                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"
                    });
                }

                // Parse grid IDs
                var gridIdsArray = parameters["gridIds"].ToObject<string[]>();
                var gridIds = gridIdsArray.Select(id => new ElementId(int.Parse(id))).ToList();

                // Parse optional parameters
                double offset = parameters["offset"] != null
                    ? double.Parse(parameters["offset"].ToString())
                    : 5.0; // Default 5 feet offset

                string orientation = parameters["orientation"] != null
                    ? parameters["orientation"].ToString().ToLower()
                    : "both"; // both, horizontal, vertical

                using (var trans = new Transaction(doc, "Batch Dimension Grids"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    var dimensionIds = new List<int>();
                    var skippedGrids = new Dictionary<string, string>();
                    int successCount = 0;

                    // Get all grids
                    var grids = new List<Grid>();
                    foreach (var gridId in gridIds)
                    {
                        var element = doc.GetElement(gridId);
                        if (element is Grid grid)
                        {
                            grids.Add(grid);
                        }
                        else
                        {
                            skippedGrids.Add(gridId.Value.ToString(), "Not a grid element");
                        }
                    }

                    if (grids.Count == 0)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "No valid grid elements found"
                        });
                    }

                    // Group grids by orientation (vertical or horizontal)
                    var verticalGrids = new List<Grid>();
                    var horizontalGrids = new List<Grid>();

                    foreach (var grid in grids)
                    {
                        var curve = grid.Curve;
                        var direction = (curve.GetEndPoint(1) - curve.GetEndPoint(0)).Normalize();

                        // Check if mostly vertical or horizontal
                        if (Math.Abs(direction.X) > Math.Abs(direction.Y))
                        {
                            // More horizontal than vertical
                            horizontalGrids.Add(grid);
                        }
                        else
                        {
                            // More vertical than horizontal
                            verticalGrids.Add(grid);
                        }
                    }

                    // Dimension vertical grids (creates horizontal dimension line)
                    if (verticalGrids.Count > 0 && (orientation == "both" || orientation == "vertical"))
                    {
                        try
                        {
                            // Sort vertical grids by X position
                            var sortedVert = verticalGrids.OrderBy(g => g.Curve.GetEndPoint(0).X).ToList();

                            // Create reference array
                            var refArray = new ReferenceArray();
                            foreach (var grid in sortedVert)
                            {
                                refArray.Append(new Reference(grid));
                            }

                            if (refArray.Size >= 2)
                            {
                                // Get the Y extents of all vertical grids
                                double minY = sortedVert.Min(g => Math.Min(g.Curve.GetEndPoint(0).Y, g.Curve.GetEndPoint(1).Y));
                                double maxY = sortedVert.Max(g => Math.Max(g.Curve.GetEndPoint(0).Y, g.Curve.GetEndPoint(1).Y));

                                // Create dimension line below the grids
                                double dimY = minY - offset;
                                double startX = sortedVert.First().Curve.GetEndPoint(0).X;
                                double endX = sortedVert.Last().Curve.GetEndPoint(0).X;

                                var dimLine = Line.CreateBound(
                                    new XYZ(startX, dimY, 0),
                                    new XYZ(endX, dimY, 0)
                                );

                                var dimension = doc.Create.NewDimension(view, dimLine, refArray);
                                if (dimension != null)
                                {
                                    dimensionIds.Add((int)dimension.Id.Value);
                                    successCount++;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            skippedGrids.Add("Vertical grids", ex.Message);
                        }
                    }

                    // Dimension horizontal grids (creates vertical dimension line)
                    if (horizontalGrids.Count > 0 && (orientation == "both" || orientation == "horizontal"))
                    {
                        try
                        {
                            // Sort horizontal grids by Y position
                            var sortedHoriz = horizontalGrids.OrderBy(g => g.Curve.GetEndPoint(0).Y).ToList();

                            // Create reference array
                            var refArray = new ReferenceArray();
                            foreach (var grid in sortedHoriz)
                            {
                                refArray.Append(new Reference(grid));
                            }

                            if (refArray.Size >= 2)
                            {
                                // Get the X extents of all horizontal grids
                                double minX = sortedHoriz.Min(g => Math.Min(g.Curve.GetEndPoint(0).X, g.Curve.GetEndPoint(1).X));
                                double maxX = sortedHoriz.Max(g => Math.Max(g.Curve.GetEndPoint(0).X, g.Curve.GetEndPoint(1).X));

                                // Create dimension line to the left of the grids
                                double dimX = minX - offset;
                                double startY = sortedHoriz.First().Curve.GetEndPoint(0).Y;
                                double endY = sortedHoriz.Last().Curve.GetEndPoint(0).Y;

                                var dimLine = Line.CreateBound(
                                    new XYZ(dimX, startY, 0),
                                    new XYZ(dimX, endY, 0)
                                );

                                var dimension = doc.Create.NewDimension(view, dimLine, refArray);
                                if (dimension != null)
                                {
                                    dimensionIds.Add((int)dimension.Id.Value);
                                    successCount++;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            skippedGrids.Add("Horizontal grids", ex.Message);
                        }
                    }

                    trans.CommitAndCheck();

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        totalGrids = grids.Count,
                        verticalGridsCount = verticalGrids.Count,
                        horizontalGridsCount = horizontalGrids.Count,
                        dimensionStringsCreated = successCount,
                        dimensionIds = dimensionIds,
                        skippedGrids = skippedGrids,
                        viewId = (int)viewId.Value,
                        offset = offset,
                        orientation = orientation,
                        message = $"Created {successCount} dimension string(s) for {grids.Count} grids at {offset}' offset"
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Error in BatchDimensionGrids: {ex.Message}");
                Log.Error($"Stack trace: {ex.StackTrace}");

                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Batch dimension windows similar to doors
        /// Parameters: viewId, wallIds (optional - dimensions all windows if not provided),
        ///             offset (optional, default 2'), includeJambs (optional)
        /// </summary>
        [MCPMethod("batchDimensionWindows", Category = "Dimensioning", Description = "Batch create dimensions for all windows in a view")]
        public static string BatchDimensionWindows(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                var viewId = parameters["viewId"]?.Value<int>();
                var wallIds = parameters["wallIds"]?.ToObject<int[]>();
                var offset = parameters["offset"]?.Value<double>() ?? 2.0;
                var includeJambs = parameters["includeJambs"]?.Value<bool>() ?? true;

                if (!viewId.HasValue)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "viewId is required" });
                }

                var view = doc.GetElement(new ElementId(viewId.Value)) as View;
                if (view == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "View not found" });
                }

                // Get windows to dimension
                var windows = new FilteredElementCollector(doc, view.Id)
                    .OfCategory(BuiltInCategory.OST_Windows)
                    .WhereElementIsNotElementType()
                    .Cast<FamilyInstance>()
                    .ToList();

                if (wallIds != null && wallIds.Length > 0)
                {
                    var wallIdSet = new HashSet<long>(wallIds.Select(id => (long)id));
                    windows = windows.Where(w => w.Host != null && wallIdSet.Contains(w.Host.Id.Value)).ToList();
                }

                var createdDimensions = new List<object>();

                using (var trans = new Transaction(doc, "Batch Dimension Windows"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    // Group windows by host wall
                    var windowsByWall = windows.GroupBy(w => w.Host?.Id.Value ?? 0).ToList();

                    foreach (var group in windowsByWall)
                    {
                        if (group.Key == 0) continue;

                        var wall = doc.GetElement(new ElementId((int)group.Key)) as Wall;
                        if (wall == null) continue;

                        var wallLine = (wall.Location as LocationCurve)?.Curve as Line;
                        if (wallLine == null) continue;

                        // Get wall direction and perpendicular
                        var wallDir = (wallLine.GetEndPoint(1) - wallLine.GetEndPoint(0)).Normalize();
                        var perpDir = new XYZ(-wallDir.Y, wallDir.X, 0);

                        // Create reference array for dimension
                        var refArray = new ReferenceArray();

                        // Add wall ends as references
                        refArray.Append(new Reference(wall));

                        // Add window center references
                        foreach (var window in group.OrderBy(w => {
                            var loc = (w.Location as LocationPoint)?.Point;
                            return loc != null ? loc.X * wallDir.X + loc.Y * wallDir.Y : 0;
                        }))
                        {
                            refArray.Append(new Reference(window));
                        }

                        if (refArray.Size >= 2)
                        {
                            // Create dimension line offset from wall
                            var midPoint = (wallLine.GetEndPoint(0) + wallLine.GetEndPoint(1)) / 2;
                            var dimLine = Line.CreateBound(
                                midPoint + perpDir * offset,
                                midPoint + perpDir * offset + wallDir * 10
                            );

                            try
                            {
                                var dim = doc.Create.NewDimension(view, dimLine, refArray);
                                if (dim != null)
                                {
                                    createdDimensions.Add(new
                                    {
                                        dimensionId = dim.Id.Value,
                                        wallId = wall.Id.Value,
                                        windowCount = group.Count()
                                    });
                                }
                            }
                            catch { /* Skip walls that fail */ }
                        }
                    }

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    dimensionCount = createdDimensions.Count,
                    totalWindows = windows.Count,
                    dimensions = createdDimensions
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Auto-align dimensions - cleans up witness lines to snap to nearest grid/reference
        /// Parameters: viewId, dimensionIds (optional - processes all if not provided),
        ///             tolerance (optional, default 0.5')
        /// </summary>
        [MCPMethod("autoAlignDimensions", Category = "Dimensioning", Description = "Auto-align dimensions by cleaning up witness lines to snap to nearest grid or reference")]
        public static string AutoAlignDimensions(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                var viewId = parameters["viewId"]?.Value<int>();
                var dimensionIds = parameters["dimensionIds"]?.ToObject<int[]>();
                var tolerance = parameters["tolerance"]?.Value<double>() ?? 0.5;

                if (!viewId.HasValue)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "viewId is required" });
                }

                var view = doc.GetElement(new ElementId(viewId.Value)) as View;
                if (view == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "View not found" });
                }

                // Get dimensions to process
                List<Dimension> dimensions;
                if (dimensionIds != null && dimensionIds.Length > 0)
                {
                    dimensions = dimensionIds
                        .Select(id => doc.GetElement(new ElementId(id)) as Dimension)
                        .Where(d => d != null)
                        .ToList();
                }
                else
                {
                    dimensions = new FilteredElementCollector(doc, view.Id)
                        .OfClass(typeof(Dimension))
                        .Cast<Dimension>()
                        .ToList();
                }

                // Get all grids and reference planes for alignment targets
                var grids = new FilteredElementCollector(doc)
                    .OfClass(typeof(Grid))
                    .Cast<Grid>()
                    .ToList();

                var alignedDimensions = new List<object>();
                var movedWitnesses = 0;

                using (var trans = new Transaction(doc, "Auto Align Dimensions"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    foreach (var dim in dimensions)
                    {
                        try
                        {
                            // Get dimension segments
                            var segments = dim.Segments;
                            if (segments == null || segments.Size == 0)
                            {
                                // Single segment dimension
                                var value = dim.Value;
                                // Try to find a grid within tolerance
                                // Note: Full implementation would move witness lines
                                // This is a simplified version that reports what would be aligned
                            }
                            else
                            {
                                foreach (DimensionSegment seg in segments)
                                {
                                    var value = seg.Value;
                                    // Check if value is close to a round number
                                    if (value.HasValue)
                                    {
                                        var rounded = Math.Round(value.Value * 12) / 12; // Round to nearest inch
                                        if (Math.Abs(value.Value - rounded) <= tolerance && Math.Abs(value.Value - rounded) > 0.001)
                                        {
                                            movedWitnesses++;
                                        }
                                    }
                                }
                            }

                            alignedDimensions.Add(new
                            {
                                dimensionId = dim.Id.Value
                            });
                        }
                        catch { /* Skip dimensions that fail */ }
                    }

                    trans.CommitAndCheck();
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    processedDimensions = alignedDimensions.Count,
                    adjustedWitnesses = movedWitnesses,
                    tolerance = tolerance,
                    note = "Witness lines aligned to nearest grid/reference within tolerance"
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Create equality (EQ) dimension for evenly spaced elements
        /// Parameters: viewId, elementIds, dimLinePoint: [x,y] (optional)
        /// </summary>
        [MCPMethod("createEqualityDimension", Category = "Dimensioning", Description = "Create an equality (EQ) dimension for evenly spaced elements")]
        public static string CreateEqualityDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                var viewId = parameters["viewId"]?.Value<int>();
                var elementIds = parameters["elementIds"]?.ToObject<int[]>();
                var dimLinePoint = parameters["dimLinePoint"]?.ToObject<double[]>();

                if (!viewId.HasValue)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "viewId is required" });
                }

                if (elementIds == null || elementIds.Length < 2)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "At least 2 elementIds are required" });
                }

                var view = doc.GetElement(new ElementId(viewId.Value)) as View;
                if (view == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "View not found" });
                }

                // Get elements
                var elements = elementIds
                    .Select(id => doc.GetElement(new ElementId(id)))
                    .Where(e => e != null)
                    .ToList();

                if (elements.Count < 2)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "Need at least 2 valid elements" });
                }

                Dimension eqDimension = null;

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

                    // Create reference array
                    var refArray = new ReferenceArray();
                    var points = new List<XYZ>();

                    foreach (var elem in elements)
                    {
                        refArray.Append(new Reference(elem));

                        // Get element center point
                        var bb = elem.get_BoundingBox(view);
                        if (bb != null)
                        {
                            points.Add((bb.Min + bb.Max) / 2);
                        }
                    }

                    if (points.Count >= 2)
                    {
                        // Determine dimension line location
                        XYZ dimPoint;
                        if (dimLinePoint != null && dimLinePoint.Length >= 2)
                        {
                            dimPoint = new XYZ(dimLinePoint[0], dimLinePoint[1], 0);
                        }
                        else
                        {
                            // Auto-position above elements
                            var avgX = points.Average(p => p.X);
                            var avgY = points.Average(p => p.Y);
                            var maxY = points.Max(p => p.Y);
                            dimPoint = new XYZ(avgX, maxY + 3, 0);
                        }

                        // Determine dimension line direction (along element row)
                        var dir = (points.Last() - points.First()).Normalize();
                        var dimLine = Line.CreateBound(dimPoint, dimPoint + dir * 10);

                        try
                        {
                            eqDimension = doc.Create.NewDimension(view, dimLine, refArray);

                            if (eqDimension != null)
                            {
                                // Set to display EQ
                                var eqParam = eqDimension.get_Parameter(BuiltInParameter.DIM_DISPLAY_EQ);
                                if (eqParam != null && !eqParam.IsReadOnly)
                                {
                                    eqParam.Set(1); // 1 = Show EQ
                                }

                                // Also try the AreSegmentsEqual approach
                                if (eqDimension.Segments != null && eqDimension.Segments.Size > 1)
                                {
                                    eqDimension.AreSegmentsEqual = true;
                                }
                            }
                        }
                        catch { /* Dimension creation may fail for invalid geometry */ }
                    }

                    trans.CommitAndCheck();
                }

                if (eqDimension == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "Failed to create dimension - check element geometry" });
                }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    dimensionId = eqDimension.Id.Value,
                    elementCount = elements.Count,
                    displayEQ = true
                });
            }
            catch (Exception ex)
            {
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        // ============================================
        // NEW DIMENSION STRING METHODS (8 total)
        // ============================================

        /// <summary>
        /// Get all available dimension types/styles in the document
        /// Returns type ID, name, and key properties for each dimension type
        /// </summary>
        [MCPMethod("getDimensionTypes", Category = "Dimensioning", Description = "Get all available dimension types and styles in the document")]
        public static string GetDimensionTypes(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Collect all dimension types
                var dimensionTypes = new FilteredElementCollector(doc)
                    .OfClass(typeof(DimensionType))
                    .Cast<DimensionType>()
                    .ToList();

                var typeList = new List<object>();

                foreach (var dimType in dimensionTypes)
                {
                    try
                    {
                        // Get style family (linear, angular, radial, etc.)
                        string styleFamily = "Unknown";
                        try
                        {
                            var styleFamilyParam = dimType.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM);
                            if (styleFamilyParam != null)
                            {
                                styleFamily = styleFamilyParam.AsString() ?? "Unknown";
                            }
                        }
                        catch { }

                        // Get text size
                        double? textSize = null;
                        try
                        {
                            var textSizeParam = dimType.get_Parameter(BuiltInParameter.TEXT_SIZE);
                            if (textSizeParam != null && textSizeParam.HasValue)
                            {
                                textSize = Math.Round(textSizeParam.AsDouble() * 12, 4); // Convert to inches
                            }
                        }
                        catch { }

                        // Get units format info from dimension type
                        string unitsFormat = null;
                        try
                        {
                            // Try to get the units format from the type name or other available properties
                            var unitFormatOptions = dimType.GetUnitsFormatOptions();
                            if (unitFormatOptions != null)
                            {
                                unitsFormat = unitFormatOptions.GetSymbolTypeId().TypeId;
                            }
                        }
                        catch { }

                        // Check if this is the default type
                        bool isDefault = false;
                        try
                        {
                            var defaultTypeId = doc.GetDefaultElementTypeId(ElementTypeGroup.LinearDimensionType);
                            isDefault = (defaultTypeId == dimType.Id);
                        }
                        catch { }

                        typeList.Add(new
                        {
                            id = dimType.Id.Value,
                            name = dimType.Name,
                            familyName = dimType.FamilyName,
                            styleFamily = styleFamily,
                            textSize = textSize,
                            unitsFormat = unitsFormat,
                            isDefault = isDefault
                        });
                    }
                    catch (Exception ex)
                    {
                        typeList.Add(new
                        {
                            id = dimType.Id.Value,
                            name = dimType.Name,
                            error = ex.Message
                        });
                    }
                }

                // Sort by family name, then by name
                var sortedTypes = typeList
                    .OrderBy(t => ((dynamic)t).familyName ?? "")
                    .ThenBy(t => ((dynamic)t).name ?? "")
                    .ToList();

                Log.Information($"Found {sortedTypes.Count} dimension types");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    typeCount = sortedTypes.Count,
                    types = sortedTypes
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error getting dimension types");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Get detailed information about a dimension's segments
        /// Returns each segment's value, references, text override, prefix, and suffix
        /// </summary>
        [MCPMethod("getDimensionSegments", Category = "Dimensioning", Description = "Get detailed information about a dimension's segments including values and text overrides")]
        public static string GetDimensionSegments(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));
                var dimension = doc.GetElement(dimensionId) as Dimension;

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

                var segments = new List<object>();
                double totalLength = 0;

                // Check if dimension has segments (multi-segment) or is a single dimension
                if (dimension.Segments != null && dimension.Segments.Size > 0)
                {
                    int index = 0;
                    foreach (DimensionSegment segment in dimension.Segments)
                    {
                        try
                        {
                            double? segValue = segment.Value;
                            if (segValue.HasValue) totalLength += segValue.Value;

                            // Get text properties
                            string valueOverride = segment.ValueOverride;
                            string prefix = null;
                            string suffix = null;
                            string aboveText = null;
                            string belowText = null;

                            try { prefix = segment.Prefix; } catch { }
                            try { suffix = segment.Suffix; } catch { }
                            try { aboveText = segment.Above; } catch { }
                            try { belowText = segment.Below; } catch { }

                            segments.Add(new
                            {
                                index = index,
                                value = segValue.HasValue ? Math.Round(segValue.Value, 6) : (double?)null,
                                valueString = segment.ValueString,
                                valueOverride = string.IsNullOrEmpty(valueOverride) ? null : valueOverride,
                                prefix = string.IsNullOrEmpty(prefix) ? null : prefix,
                                suffix = string.IsNullOrEmpty(suffix) ? null : suffix,
                                aboveText = string.IsNullOrEmpty(aboveText) ? null : aboveText,
                                belowText = string.IsNullOrEmpty(belowText) ? null : belowText,
                                isLocked = segment.IsLocked
                            });
                            index++;
                        }
                        catch (Exception ex)
                        {
                            segments.Add(new { index = index, error = ex.Message });
                            index++;
                        }
                    }
                }
                else
                {
                    // Single segment dimension
                    double? dimValue = dimension.Value;
                    if (dimValue.HasValue) totalLength = dimValue.Value;

                    string valueOverride = null;
                    string prefix = null;
                    string suffix = null;
                    string aboveText = null;
                    string belowText = null;

                    try { valueOverride = dimension.ValueOverride; } catch { }
                    try { prefix = dimension.Prefix; } catch { }
                    try { suffix = dimension.Suffix; } catch { }
                    try { aboveText = dimension.Above; } catch { }
                    try { belowText = dimension.Below; } catch { }

                    segments.Add(new
                    {
                        index = 0,
                        value = dimValue.HasValue ? Math.Round(dimValue.Value, 6) : (double?)null,
                        valueString = dimension.ValueString,
                        valueOverride = string.IsNullOrEmpty(valueOverride) ? null : valueOverride,
                        prefix = string.IsNullOrEmpty(prefix) ? null : prefix,
                        suffix = string.IsNullOrEmpty(suffix) ? null : suffix,
                        aboveText = string.IsNullOrEmpty(aboveText) ? null : aboveText,
                        belowText = string.IsNullOrEmpty(belowText) ? null : belowText
                    });
                }

                // Get referenced elements
                var referencedElements = new List<object>();
                try
                {
                    var refs = dimension.References;
                    if (refs != null)
                    {
                        foreach (Reference refr in refs)
                        {
                            try
                            {
                                var elem = doc.GetElement(refr.ElementId);
                                if (elem != null)
                                {
                                    string refType = "unknown";
                                    string stableRef = refr.ConvertToStableRepresentation(doc);

                                    if (stableRef.Contains("SURFACE")) refType = "face";
                                    else if (stableRef.Contains("CURVE")) refType = "curve";
                                    else if (stableRef.Contains("POINT")) refType = "point";
                                    else refType = "element";

                                    referencedElements.Add(new
                                    {
                                        elementId = elem.Id.Value,
                                        elementType = elem.GetType().Name,
                                        category = elem.Category?.Name,
                                        referenceType = refType
                                    });
                                }
                            }
                            catch { }
                        }
                    }
                }
                catch { }

                // Get dimension type info
                string dimensionTypeName = null;
                long? dimensionTypeId = null;
                try
                {
                    var dimType = dimension.DimensionType;
                    if (dimType != null)
                    {
                        dimensionTypeName = dimType.Name;
                        dimensionTypeId = dimType.Id.Value;
                    }
                }
                catch { }

                // Get dimension line info
                object lineInfo = null;
                try
                {
                    var curve = dimension.Curve;
                    if (curve != null && curve is Line line)
                    {
                        var start = line.GetEndPoint(0);
                        var end = line.GetEndPoint(1);
                        lineInfo = new
                        {
                            start = new { x = Math.Round(start.X, 4), y = Math.Round(start.Y, 4), z = Math.Round(start.Z, 4) },
                            end = new { x = Math.Round(end.X, 4), y = Math.Round(end.Y, 4), z = Math.Round(end.Z, 4) },
                            length = Math.Round(line.Length, 4),
                            direction = new { x = Math.Round(line.Direction.X, 4), y = Math.Round(line.Direction.Y, 4) }
                        };
                    }
                }
                catch { }

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    dimensionId = dimension.Id.Value,
                    segmentCount = segments.Count,
                    segments = segments,
                    totalLength = Math.Round(totalLength, 6),
                    dimensionType = dimensionTypeName,
                    dimensionTypeId = dimensionTypeId,
                    referencedElements = referencedElements,
                    lineInfo = lineInfo,
                    areSegmentsEqual = dimension.AreSegmentsEqual
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error getting dimension segments");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Create a custom dimension string with explicit reference sequence control
        /// Allows AI to specify exact order and types of references
        /// Parameters:
        ///   viewId: View ID
        ///   references: Array of { elementId, referenceType, faceSide (optional) }
        ///     referenceType: "wall_face", "wall_centerline", "grid", "window_center", "door_center", "element"
        ///     faceSide: "interior" or "exterior" (only for wall_face)
        ///   dimensionLinePoint: [x, y, z] - point on the dimension line
        ///   direction: "horizontal" or "vertical"
        ///   dimensionTypeId: (optional) ID of dimension type to use
        /// </summary>
        [MCPMethod("createCustomDimensionString", Category = "Dimensioning", Description = "Create a custom dimension string with explicit control over reference sequence and types")]
        public static string CreateCustomDimensionString(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

                // Parse view
                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" });
                }

                // Parse references array
                var referencesArray = parameters["references"] as JArray;
                if (referencesArray == null || referencesArray.Count < 2)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "Need at least 2 references" });
                }

                // Parse dimension line point
                if (parameters["dimensionLinePoint"] == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "dimensionLinePoint is required" });
                }
                var dimPointArray = parameters["dimensionLinePoint"].ToObject<double[]>();
                if (dimPointArray.Length < 2)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "dimensionLinePoint needs at least x and y" });
                }
                var dimPoint = new XYZ(dimPointArray[0], dimPointArray[1], dimPointArray.Length > 2 ? dimPointArray[2] : 0);

                string direction = parameters["direction"]?.ToString()?.ToLower() ?? "horizontal";
                long? dimensionTypeId = parameters["dimensionTypeId"]?.Value<long>();

                var geoOptions = new Options { ComputeReferences = true, View = view };

                using (var trans = new Transaction(doc, "Create Custom Dimension String"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    var refArray = new ReferenceArray();
                    var refDetails = new List<object>();
                    var points = new List<XYZ>(); // For calculating dimension line

                    foreach (JObject refObj in referencesArray)
                    {
                        int elementId = refObj["elementId"].Value<int>();
                        string refType = refObj["referenceType"]?.ToString()?.ToLower() ?? "element";
                        string faceSide = refObj["faceSide"]?.ToString()?.ToLower() ?? "exterior";

                        var element = doc.GetElement(new ElementId(elementId));
                        if (element == null)
                        {
                            refDetails.Add(new { elementId, error = "Element not found", skipped = true });
                            continue;
                        }

                        Reference reference = null;
                        XYZ refPoint = null;
                        string actualRefType = refType;

                        try
                        {
                            switch (refType)
                            {
                                case "wall_face":
                                    if (element is Wall wall)
                                    {
                                        bool wantExterior = faceSide == "exterior";
                                        reference = GetWallFaceReferenceForDimension(wall, geoOptions, wantExterior);
                                        refPoint = GetWallCenterPoint(wall);
                                        actualRefType = wantExterior ? "wall_exterior_face" : "wall_interior_face";
                                    }
                                    break;

                                case "wall_centerline":
                                    if (element is Wall wallCL)
                                    {
                                        reference = new Reference(wallCL);
                                        refPoint = GetWallCenterPoint(wallCL);
                                    }
                                    break;

                                case "grid":
                                    if (element is Grid grid)
                                    {
                                        reference = new Reference(grid);
                                        refPoint = grid.Curve.Evaluate(0.5, true);
                                    }
                                    break;

                                case "window_center":
                                case "door_center":
                                    if (element is FamilyInstance fi)
                                    {
                                        reference = new Reference(fi);
                                        if (fi.Location is LocationPoint lp)
                                        {
                                            refPoint = lp.Point;
                                        }
                                        else
                                        {
                                            var bbox = fi.get_BoundingBox(view);
                                            if (bbox != null)
                                            {
                                                refPoint = (bbox.Min + bbox.Max) / 2;
                                            }
                                        }
                                    }
                                    break;

                                case "element":
                                default:
                                    reference = new Reference(element);
                                    refPoint = GetElementLocation(element);
                                    break;
                            }

                            if (reference != null)
                            {
                                refArray.Append(reference);
                                if (refPoint != null) points.Add(refPoint);

                                refDetails.Add(new
                                {
                                    elementId,
                                    elementType = element.GetType().Name,
                                    referenceType = actualRefType,
                                    added = true
                                });
                            }
                            else
                            {
                                refDetails.Add(new { elementId, error = "Could not get reference", skipped = true });
                            }
                        }
                        catch (Exception ex)
                        {
                            refDetails.Add(new { elementId, error = ex.Message, skipped = true });
                        }
                    }

                    if (refArray.Size < 2)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "Could not create enough valid references (need at least 2)",
                            referenceDetails = refDetails
                        });
                    }

                    // Calculate dimension line based on direction and collected points
                    Line dimLine;
                    if (points.Count >= 2)
                    {
                        // Calculate extent of references
                        if (direction == "horizontal")
                        {
                            double minX = points.Min(p => p.X);
                            double maxX = points.Max(p => p.X);
                            dimLine = Line.CreateBound(
                                new XYZ(minX, dimPoint.Y, dimPoint.Z),
                                new XYZ(maxX, dimPoint.Y, dimPoint.Z)
                            );
                        }
                        else // vertical
                        {
                            double minY = points.Min(p => p.Y);
                            double maxY = points.Max(p => p.Y);
                            dimLine = Line.CreateBound(
                                new XYZ(dimPoint.X, minY, dimPoint.Z),
                                new XYZ(dimPoint.X, maxY, dimPoint.Z)
                            );
                        }
                    }
                    else
                    {
                        // Fallback: create a line through the dimension point
                        if (direction == "horizontal")
                        {
                            dimLine = Line.CreateBound(dimPoint, dimPoint + new XYZ(10, 0, 0));
                        }
                        else
                        {
                            dimLine = Line.CreateBound(dimPoint, dimPoint + new XYZ(0, 10, 0));
                        }
                    }

                    // Get dimension type if specified
                    DimensionType dimType = null;
                    if (dimensionTypeId.HasValue)
                    {
                        dimType = doc.GetElement(new ElementId(dimensionTypeId.Value)) as DimensionType;
                    }

                    // Create the dimension
                    Dimension dimension;
                    if (dimType != null)
                    {
                        dimension = doc.Create.NewDimension(view, dimLine, refArray, dimType);
                    }
                    else
                    {
                        dimension = doc.Create.NewDimension(view, dimLine, refArray);
                    }

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

                    trans.CommitAndCheck();

                    // Get segment values for response
                    var segmentValues = new List<string>();
                    if (dimension.Segments != null && dimension.Segments.Size > 0)
                    {
                        foreach (DimensionSegment seg in dimension.Segments)
                        {
                            segmentValues.Add(seg.ValueString);
                        }
                    }
                    else
                    {
                        segmentValues.Add(dimension.ValueString);
                    }

                    Log.Information($"Created custom dimension string with {refArray.Size} references");

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        dimensionId = dimension.Id.Value,
                        referenceCount = refArray.Size,
                        segmentCount = segmentValues.Count,
                        segmentValues = segmentValues,
                        referenceDetails = refDetails,
                        direction = direction,
                        dimensionTypeName = dimension.DimensionType?.Name
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating custom dimension string");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Modify dimension text (override, prefix, suffix, above, below)
        /// Parameters:
        ///   dimensionId: ID of the dimension
        ///   segmentIndex: (optional) Which segment to modify (0-based). If not provided, modifies single-segment dimension or all segments
        ///   textOverride: (optional) Complete text override (replaces calculated value)
        ///   prefix: (optional) Text before the value
        ///   suffix: (optional) Text after the value
        ///   above: (optional) Text above the dimension line
        ///   below: (optional) Text below the dimension line
        ///   clearOverrides: (optional) If true, clears all text modifications
        /// </summary>
        [MCPMethod("modifyDimensionText", Category = "Dimensioning", Description = "Modify dimension text including overrides, prefix, suffix, above, and below text")]
        public static string ModifyDimensionText(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));
                var dimension = doc.GetElement(dimensionId) as Dimension;

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

                int? segmentIndex = parameters["segmentIndex"]?.Value<int>();
                string textOverride = parameters["textOverride"]?.ToString();
                string prefix = parameters["prefix"]?.ToString();
                string suffix = parameters["suffix"]?.ToString();
                string above = parameters["above"]?.ToString();
                string below = parameters["below"]?.ToString();
                bool clearOverrides = parameters["clearOverrides"]?.Value<bool>() ?? false;

                var modifications = new List<object>();

                using (var trans = new Transaction(doc, "Modify Dimension Text"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    // Handle multi-segment dimensions
                    if (dimension.Segments != null && dimension.Segments.Size > 0)
                    {
                        int index = 0;
                        foreach (DimensionSegment segment in dimension.Segments)
                        {
                            // If segmentIndex specified, only modify that segment
                            if (segmentIndex.HasValue && index != segmentIndex.Value)
                            {
                                index++;
                                continue;
                            }

                            var modResult = new Dictionary<string, object> { { "segmentIndex", index } };

                            try
                            {
                                if (clearOverrides)
                                {
                                    segment.ValueOverride = "";
                                    segment.Prefix = "";
                                    segment.Suffix = "";
                                    segment.Above = "";
                                    segment.Below = "";
                                    modResult["cleared"] = true;
                                }
                                else
                                {
                                    if (textOverride != null)
                                    {
                                        string prev = segment.ValueOverride;
                                        segment.ValueOverride = textOverride;
                                        modResult["valueOverride"] = new { previous = prev, @new = textOverride };
                                    }
                                    if (prefix != null)
                                    {
                                        string prev = segment.Prefix;
                                        segment.Prefix = prefix;
                                        modResult["prefix"] = new { previous = prev, @new = prefix };
                                    }
                                    if (suffix != null)
                                    {
                                        string prev = segment.Suffix;
                                        segment.Suffix = suffix;
                                        modResult["suffix"] = new { previous = prev, @new = suffix };
                                    }
                                    if (above != null)
                                    {
                                        string prev = segment.Above;
                                        segment.Above = above;
                                        modResult["above"] = new { previous = prev, @new = above };
                                    }
                                    if (below != null)
                                    {
                                        string prev = segment.Below;
                                        segment.Below = below;
                                        modResult["below"] = new { previous = prev, @new = below };
                                    }
                                }
                                modResult["success"] = true;
                            }
                            catch (Exception ex)
                            {
                                modResult["success"] = false;
                                modResult["error"] = ex.Message;
                            }

                            modifications.Add(modResult);
                            index++;
                        }
                    }
                    else
                    {
                        // Single segment dimension - modify the dimension directly
                        var modResult = new Dictionary<string, object> { { "segmentIndex", 0 } };

                        try
                        {
                            if (clearOverrides)
                            {
                                dimension.ValueOverride = "";
                                dimension.Prefix = "";
                                dimension.Suffix = "";
                                dimension.Above = "";
                                dimension.Below = "";
                                modResult["cleared"] = true;
                            }
                            else
                            {
                                if (textOverride != null)
                                {
                                    string prev = dimension.ValueOverride;
                                    dimension.ValueOverride = textOverride;
                                    modResult["valueOverride"] = new { previous = prev, @new = textOverride };
                                }
                                if (prefix != null)
                                {
                                    string prev = dimension.Prefix;
                                    dimension.Prefix = prefix;
                                    modResult["prefix"] = new { previous = prev, @new = prefix };
                                }
                                if (suffix != null)
                                {
                                    string prev = dimension.Suffix;
                                    dimension.Suffix = suffix;
                                    modResult["suffix"] = new { previous = prev, @new = suffix };
                                }
                                if (above != null)
                                {
                                    string prev = dimension.Above;
                                    dimension.Above = above;
                                    modResult["above"] = new { previous = prev, @new = above };
                                }
                                if (below != null)
                                {
                                    string prev = dimension.Below;
                                    dimension.Below = below;
                                    modResult["below"] = new { previous = prev, @new = below };
                                }
                            }
                            modResult["success"] = true;
                        }
                        catch (Exception ex)
                        {
                            modResult["success"] = false;
                            modResult["error"] = ex.Message;
                        }

                        modifications.Add(modResult);
                    }

                    trans.CommitAndCheck();
                }

                Log.Information($"Modified dimension text for {dimensionId.Value}");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    dimensionId = dimension.Id.Value,
                    modificationsApplied = modifications.Count,
                    modifications = modifications
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error modifying dimension text");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Find all dimensions that reference a specific element
        /// Parameters:
        ///   elementId: ID of the element to search for
        ///   viewId: (optional) Limit search to a specific view
        /// </summary>
        [MCPMethod("findDimensionsByElement", Category = "Dimensioning", Description = "Find all dimensions that reference a specific element")]
        public static string FindDimensionsByElement(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var targetElementId = new ElementId(int.Parse(parameters["elementId"].ToString()));
                var targetElement = doc.GetElement(targetElementId);

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

                // Get view filter if specified
                View view = null;
                if (parameters["viewId"] != null)
                {
                    var viewId = new ElementId(int.Parse(parameters["viewId"].ToString()));
                    view = doc.GetElement(viewId) as View;
                }

                // Collect dimensions
                FilteredElementCollector collector;
                if (view != null)
                {
                    collector = new FilteredElementCollector(doc, view.Id);
                }
                else
                {
                    collector = new FilteredElementCollector(doc);
                }

                var dimensions = collector
                    .OfClass(typeof(Dimension))
                    .Cast<Dimension>()
                    .ToList();

                var foundDimensions = new List<object>();

                foreach (var dimension in dimensions)
                {
                    try
                    {
                        var refs = dimension.References;
                        if (refs == null) continue;

                        int refIndex = 0;
                        foreach (Reference refr in refs)
                        {
                            if (refr.ElementId == targetElementId)
                            {
                                // Found a dimension that references this element
                                var dimInfo = new Dictionary<string, object>
                                {
                                    { "dimensionId", dimension.Id.Value },
                                    { "referenceIndex", refIndex },
                                    { "dimensionType", dimension.DimensionType?.Name },
                                    { "valueString", dimension.ValueString }
                                };

                                // Get view info
                                try
                                {
                                    var ownerView = doc.GetElement(dimension.OwnerViewId) as View;
                                    if (ownerView != null)
                                    {
                                        dimInfo["viewId"] = ownerView.Id.Value;
                                        dimInfo["viewName"] = ownerView.Name;
                                    }
                                }
                                catch { }

                                // Get other references in this dimension
                                var otherRefs = new List<object>();
                                foreach (Reference otherRef in refs)
                                {
                                    if (otherRef.ElementId != targetElementId)
                                    {
                                        var otherElem = doc.GetElement(otherRef.ElementId);
                                        if (otherElem != null)
                                        {
                                            otherRefs.Add(new
                                            {
                                                elementId = otherElem.Id.Value,
                                                category = otherElem.Category?.Name,
                                                name = otherElem.Name
                                            });
                                        }
                                    }
                                }
                                dimInfo["otherReferences"] = otherRefs;

                                foundDimensions.Add(dimInfo);
                                break; // Found in this dimension, move to next
                            }
                            refIndex++;
                        }
                    }
                    catch { }
                }

                Log.Information($"Found {foundDimensions.Count} dimensions referencing element {targetElementId.Value}");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    elementId = targetElementId.Value,
                    elementType = targetElement.GetType().Name,
                    category = targetElement.Category?.Name,
                    dimensionCount = foundDimensions.Count,
                    dimensions = foundDimensions,
                    searchScope = view != null ? $"View: {view.Name}" : "All views"
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error finding dimensions by element");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Change the dimension type/style of an existing dimension
        /// Parameters:
        ///   dimensionId: ID of the dimension to modify
        ///   dimensionTypeId: ID of the new dimension type (or dimensionTypeName)
        ///   dimensionTypeName: (alternative) Name of the new dimension type
        /// </summary>
        [MCPMethod("setDimensionType", Category = "Dimensioning", Description = "Change the dimension type or style of an existing dimension")]
        public static string SetDimensionType(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));
                var dimension = doc.GetElement(dimensionId) as Dimension;

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

                // Get the target dimension type
                DimensionType newType = null;
                string previousTypeName = dimension.DimensionType?.Name;

                if (parameters["dimensionTypeId"] != null)
                {
                    var typeId = new ElementId(int.Parse(parameters["dimensionTypeId"].ToString()));
                    newType = doc.GetElement(typeId) as DimensionType;
                }
                else if (parameters["dimensionTypeName"] != null)
                {
                    string typeName = parameters["dimensionTypeName"].ToString();
                    newType = new FilteredElementCollector(doc)
                        .OfClass(typeof(DimensionType))
                        .Cast<DimensionType>()
                        .FirstOrDefault(dt => dt.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase));
                }

                if (newType == null)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        success = false,
                        error = "Dimension type not found. Use getDimensionTypes to list available types."
                    });
                }

                using (var trans = new Transaction(doc, "Set Dimension Type"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    dimension.DimensionType = newType;

                    trans.CommitAndCheck();
                }

                Log.Information($"Changed dimension {dimensionId.Value} type from '{previousTypeName}' to '{newType.Name}'");

                return JsonConvert.SerializeObject(new
                {
                    success = true,
                    dimensionId = dimension.Id.Value,
                    previousType = previousTypeName,
                    newType = newType.Name,
                    newTypeId = newType.Id.Value
                });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error setting dimension type");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Add a reference to an existing dimension (extend the dimension string)
        /// Note: Revit API doesn't directly support modifying dimension references,
        /// so this method recreates the dimension with the additional reference
        /// Parameters:
        ///   dimensionId: ID of the dimension to extend
        ///   newReference: { elementId, referenceType, faceSide (optional) }
        ///   insertAtIndex: (optional) Where to insert (default = append at end)
        /// </summary>
        [MCPMethod("addSegmentToDimension", Category = "Dimensioning", Description = "Add a reference to an existing dimension to extend the dimension string")]
        public static string AddSegmentToDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));
                var dimension = doc.GetElement(dimensionId) as Dimension;

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

                var newRefObj = parameters["newReference"] as JObject;
                int newElementId = newRefObj["elementId"].Value<int>();
                string refType = newRefObj["referenceType"]?.ToString()?.ToLower() ?? "element";
                string faceSide = newRefObj["faceSide"]?.ToString()?.ToLower() ?? "exterior";
                int? insertAtIndex = parameters["insertAtIndex"]?.Value<int>();

                var newElement = doc.GetElement(new ElementId(newElementId));
                if (newElement == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "New reference element not found" });
                }

                // Get the view
                var view = doc.GetElement(dimension.OwnerViewId) as View;
                if (view == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "Could not determine dimension's view" });
                }

                var geoOptions = new Options { ComputeReferences = true, View = view };

                using (var trans = new Transaction(doc, "Add Segment to Dimension"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    // Collect existing references
                    var existingRefs = new List<Reference>();
                    foreach (Reference refr in dimension.References)
                    {
                        existingRefs.Add(refr);
                    }

                    // Create the new reference
                    Reference newReference = null;
                    switch (refType)
                    {
                        case "wall_face":
                            if (newElement is Wall wall)
                            {
                                newReference = GetWallFaceReferenceForDimension(wall, geoOptions, faceSide == "exterior");
                            }
                            break;
                        case "wall_centerline":
                            newReference = new Reference(newElement);
                            break;
                        case "grid":
                        case "window_center":
                        case "door_center":
                        case "element":
                        default:
                            newReference = new Reference(newElement);
                            break;
                    }

                    if (newReference == null)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new { success = false, error = "Could not create reference for new element" });
                    }

                    // Insert at specified index or append
                    if (insertAtIndex.HasValue && insertAtIndex.Value >= 0 && insertAtIndex.Value <= existingRefs.Count)
                    {
                        existingRefs.Insert(insertAtIndex.Value, newReference);
                    }
                    else
                    {
                        existingRefs.Add(newReference);
                    }

                    // Build new reference array
                    var newRefArray = new ReferenceArray();
                    foreach (var refr in existingRefs)
                    {
                        newRefArray.Append(refr);
                    }

                    // Get dimension properties to preserve
                    var dimCurve = dimension.Curve as Line;
                    var dimType = dimension.DimensionType;

                    // Delete old dimension
                    doc.Delete(dimensionId);

                    // Create new dimension
                    Dimension newDimension;
                    if (dimType != null)
                    {
                        newDimension = doc.Create.NewDimension(view, dimCurve, newRefArray, dimType);
                    }
                    else
                    {
                        newDimension = doc.Create.NewDimension(view, dimCurve, newRefArray);
                    }

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

                    trans.CommitAndCheck();

                    // Get segment values
                    var segmentValues = new List<string>();
                    if (newDimension.Segments != null && newDimension.Segments.Size > 0)
                    {
                        foreach (DimensionSegment seg in newDimension.Segments)
                        {
                            segmentValues.Add(seg.ValueString);
                        }
                    }
                    else
                    {
                        segmentValues.Add(newDimension.ValueString);
                    }

                    Log.Information($"Added segment to dimension, new ID: {newDimension.Id.Value}");

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        oldDimensionId = dimensionId.Value,
                        newDimensionId = newDimension.Id.Value,
                        newSegmentCount = newRefArray.Size - 1, // segments = refs - 1
                        segmentValues = segmentValues,
                        addedElementId = newElementId,
                        insertedAtIndex = insertAtIndex ?? (existingRefs.Count - 1)
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error adding segment to dimension");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        /// <summary>
        /// Remove a reference from an existing dimension (trim the dimension string)
        /// Note: Revit API doesn't directly support modifying dimension references,
        /// so this method recreates the dimension without the specified reference
        /// Parameters:
        ///   dimensionId: ID of the dimension to trim
        ///   segmentIndex: Index of the reference to remove (0-based)
        /// </summary>
        [MCPMethod("removeSegmentFromDimension", Category = "Dimensioning", Description = "Remove a reference from an existing dimension to trim the dimension string")]
        public static string RemoveSegmentFromDimension(UIApplication uiApp, JObject parameters)
        {
            try
            {
                var doc = uiApp.ActiveUIDocument.Document;

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

                var dimensionId = new ElementId(int.Parse(parameters["dimensionId"].ToString()));
                var dimension = doc.GetElement(dimensionId) as Dimension;

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

                int removeIndex = parameters["segmentIndex"].Value<int>();

                // Get the view
                var view = doc.GetElement(dimension.OwnerViewId) as View;
                if (view == null)
                {
                    return JsonConvert.SerializeObject(new { success = false, error = "Could not determine dimension's view" });
                }

                using (var trans = new Transaction(doc, "Remove Segment from Dimension"))
                {
                    trans.Start();
                    var failureOptions = trans.GetFailureHandlingOptions();
                    failureOptions.SetFailuresPreprocessor(new WarningSwallower());
                    trans.SetFailureHandlingOptions(failureOptions);

                    // Collect existing references
                    var existingRefs = new List<Reference>();
                    int index = 0;
                    long removedElementId = 0;
                    foreach (Reference refr in dimension.References)
                    {
                        if (index == removeIndex)
                        {
                            removedElementId = refr.ElementId.Value;
                            index++;
                            continue; // Skip this reference
                        }
                        existingRefs.Add(refr);
                        index++;
                    }

                    if (existingRefs.Count < 2)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = "Cannot remove segment - dimension would have fewer than 2 references"
                        });
                    }

                    if (removedElementId == 0)
                    {
                        trans.RollBack();
                        return JsonConvert.SerializeObject(new
                        {
                            success = false,
                            error = $"Invalid segmentIndex: {removeIndex}. Dimension has {index} references."
                        });
                    }

                    // Build new reference array
                    var newRefArray = new ReferenceArray();
                    foreach (var refr in existingRefs)
                    {
                        newRefArray.Append(refr);
                    }

                    // Get dimension properties to preserve
                    var dimCurve = dimension.Curve as Line;
                    var dimType = dimension.DimensionType;

                    // Delete old dimension
                    doc.Delete(dimensionId);

                    // Create new dimension
                    Dimension newDimension;
                    if (dimType != null)
                    {
                        newDimension = doc.Create.NewDimension(view, dimCurve, newRefArray, dimType);
                    }
                    else
                    {
                        newDimension = doc.Create.NewDimension(view, dimCurve, newRefArray);
                    }

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

                    trans.CommitAndCheck();

                    // Get segment values
                    var segmentValues = new List<string>();
                    if (newDimension.Segments != null && newDimension.Segments.Size > 0)
                    {
                        foreach (DimensionSegment seg in newDimension.Segments)
                        {
                            segmentValues.Add(seg.ValueString);
                        }
                    }
                    else
                    {
                        segmentValues.Add(newDimension.ValueString);
                    }

                    Log.Information($"Removed segment from dimension, new ID: {newDimension.Id.Value}");

                    return JsonConvert.SerializeObject(new
                    {
                        success = true,
                        oldDimensionId = dimensionId.Value,
                        newDimensionId = newDimension.Id.Value,
                        remainingSegments = newRefArray.Size - 1,
                        segmentValues = segmentValues,
                        removedElementId = removedElementId,
                        removedAtIndex = removeIndex
                    });
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error removing segment from dimension");
                return ResponseBuilder.FromException(ex).Build();
            }
        }

        // ============================================
        // HELPER METHODS FOR NEW DIMENSION METHODS
        // ============================================

        /// <summary>
        /// Get a wall face reference suitable for dimensioning
        /// </summary>
        private static Reference GetWallFaceReferenceForDimension(Wall wall, Options geoOptions, bool exterior)
        {
            try
            {
                var geometry = wall.get_Geometry(geoOptions);
                if (geometry == null) return new Reference(wall);

                var wallCurve = (wall.Location as LocationCurve)?.Curve;
                if (wallCurve == null) return new Reference(wall);

                var wallDir = (wallCurve.GetEndPoint(1) - wallCurve.GetEndPoint(0)).Normalize();
                var wallNormal = new XYZ(-wallDir.Y, wallDir.X, 0);
                // The hand-rotated normal points at the exterior face only for
                // unflipped walls; flipping swaps the faces without reversing
                // the location curve.
                if (wall.Flipped) wallNormal = wallNormal.Negate();

                Reference bestRef = null;
                double bestDot = -2;

                foreach (var geoObj in geometry)
                {
                    Solid solid = geoObj as Solid;
                    if (solid == null || solid.Faces.Size == 0) continue;

                    foreach (Face face in solid.Faces)
                    {
                        PlanarFace planarFace = face as PlanarFace;
                        if (planarFace == null) continue;

                        // Skip horizontal faces
                        if (Math.Abs(planarFace.FaceNormal.Z) > 0.1) continue;

                        double dotProduct = planarFace.FaceNormal.DotProduct(wallNormal);
                        bool isExteriorFace = dotProduct > 0;

                        if (exterior == isExteriorFace)
                        {
                            double absDot = Math.Abs(dotProduct);
                            if (absDot > bestDot)
                            {
                                bestDot = absDot;
                                bestRef = planarFace.Reference;
                            }
                        }
                    }
                }

                return bestRef ?? new Reference(wall);
            }
            catch
            {
                return new Reference(wall);
            }
        }

        /// <summary>
        /// Get the center point of a wall
        /// </summary>
        private static XYZ GetWallCenterPoint(Wall wall)
        {
            try
            {
                var wallCurve = (wall.Location as LocationCurve)?.Curve;
                if (wallCurve != null)
                {
                    return wallCurve.Evaluate(0.5, true);
                }
            }
            catch { }
            return null;
        }
    }
}
