using System.ComponentModel;
using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Editing;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
using Kompas.Mcp.Core.Validation;
using ModelContextProtocol.Server;

namespace Kompas.Mcp.Host.Tools;

/// <summary>Инструменты прямого редактирования тела (без дерева построения).</summary>
[McpServerToolType]
public sealed class EditTools(
    KompasSession session,
    FaceEditService faceEdit,
    SolidEditService solidEdit,
    ModelInspectionService inspection,
    AutoValidation autoValidation)
{
    [McpServerTool(Name = "move_face")]
    [Description("Прямое редактирование («Переместить грань»): сдвинуть грань детали на distance мм вдоль её " +
                 "нормали. distance>0 — наружу (добавить материал, удлинить деталь), distance<0 — внутрь; " +
                 "направление нормали подбирается автоматически. Грань задаётся ЛИБО faceIndex из list_faces " +
                 "(надёжнее), ЛИБО точкой x,y,z на грани в мировых координатах модели. " +
                 "Работает и на импортированной (STEP) геометрии без дерева построения.")]
    public async Task<string> MoveFace(
        [Description("Смещение вдоль нормали, мм (>0 — наружу, <0 — внутрь)")] double distance,
        [Description("Индекс грани из list_faces")] int? faceIndex = null,
        [Description("X точки на грани, мм")] double? x = null,
        [Description("Y точки на грани, мм")] double? y = null,
        [Description("Z точки на грани, мм")] double? z = null,
        [Description("Имя операции в дереве построения, например «Наращивание торца»")] string? name = null)
    {
        await session.ConnectAsync();

        double px, py, pz;
        string where;
        if (faceIndex is { } fi)
        {
            (px, py, pz) = await inspection.FaceCenterPointAsync(fi);
            where = $"Грань [{fi}]";
        }
        else if (x is { } ax && y is { } ay && z is { } az)
        {
            (px, py, pz) = (ax, ay, az);
            where = $"Грань в точке ({ax}, {ay}, {az})";
        }
        else
        {
            throw new ArgumentException(
                "Не задана грань: передайте faceIndex из list_faces (надёжнее) либо все три координаты точки на грани (x, y, z).");
        }

        await faceEdit.MoveFaceAsync(px, py, pz, distance, name);
        return await autoValidation.AnnotateAsync($"{where} перемещена на {distance} мм вдоль нормали.");
    }

    [McpServerTool(Name = "split_solid_by_plane")]
    [Description("Рассечь тело активной детали смещённой плоскостью: база plane (XOY|XOZ|YOZ) + offset мм. " +
                 "Получаются отдельные тела — возвращает их список с индексом и габаритом по осям, чтобы выбрать " +
                 "тело для move_body. Шаг 1 метода «рассечь→раздвинуть→объединить».")]
    public async Task<string> SplitSolidByPlane(
        [Description("Базовая плоскость: XOY | XOZ | YOZ")] string plane,
        [Description("Смещение плоскости от базовой, мм")] double offset,
        [Description("Прямое направление отступа")] bool direction = true,
        [Description("Имя операции в дереве построения, например «Рез под вставку 5 мм»")] string? name = null)
    {
        await session.ConnectAsync();
        var bodies = await solidEdit.SplitByPlaneAsync(BasePlanes.Parse(plane), offset, direction, name);
        var lines = bodies.Select(b =>
            $"  [{b.Index}] габ {b.SizeX:F1}×{b.SizeY:F1}×{b.SizeZ:F1} мм, " +
            $"Z[{b.MinZ:F1}; {b.MaxZ:F1}]");
        return $"Рассечение {plane}+{offset}: тел стало {bodies.Count}\n" + string.Join("\n", lines);
    }

    [McpServerTool(Name = "move_body")]
    [Description("Переместить тело (по индексу из split_solid_by_plane) на вектор (dx, dy, dz) мм. " +
                 "Шаг 2 метода «рассечь→раздвинуть→объединить» — раздвигает части на нужный зазор.")]
    public async Task<string> MoveBody(int bodyIndex, double dx = 0, double dy = 0, double dz = 0,
        [Description("Имя операции в дереве построения, например «Раздвижка верхней части»")] string? name = null)
    {
        await session.ConnectAsync();
        await solidEdit.MoveBodyAsync(bodyIndex, dx, dy, dz, name);
        return await autoValidation.AnnotateAsync($"Тело [{bodyIndex}] перемещено на ({dx}, {dy}, {dz}) мм.");
    }

    [McpServerTool(Name = "boolean_union")]
    [Description("Объединить все тела активной детали в одно (булева операция «объединение»). " +
                 "Шаг 4 (финал) метода «рассечь→раздвинуть→объединить»: после стыковки граней (move_face) " +
                 "сливает части в единое тело.")]
    public async Task<string> BooleanUnion(
        [Description("Имя операции в дереве построения, например «Сшивка частей корпуса»")] string? name = null)
    {
        await session.ConnectAsync();
        await solidEdit.UnionAllAsync(name);
        return await autoValidation.AnnotateAsync("Тела объединены.");
    }
}
