using System.ComponentModel;
using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Editing;
using Kompas.Mcp.Core.Modeling;
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,
    ValidationService validation)
{
    [McpServerTool(Name = "move_face")]
    [Description("Прямое редактирование («Переместить грань»): сдвинуть грань детали, найденную по мировой точке " +
                 "(x,y,z в мм, точка должна лежать на грани), на distance мм вдоль её нормали. distance>0 — наружу " +
                 "(добавить материал, удлинить деталь), distance<0 — внутрь. Направление нормали подбирается автоматически. " +
                 "Работает и на импортированной (STEP) геометрии без дерева построения. Перед вызовом сделайте " +
                 "model_snapshot/list_faces и прикиньте точку на нужной грани.")]
    public async Task<string> MoveFace(double x, double y, double z, double distance)
    {
        await session.ConnectAsync();
        await faceEdit.MoveFaceAsync(x, y, z, distance);
        return await WithValidation($"Грань в точке ({x}, {y}, {z}) перемещена на {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)
    {
        await session.ConnectAsync();
        var bodies = await solidEdit.SplitByPlaneAsync(BasePlanes.Parse(plane), offset, direction);
        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)
    {
        await session.ConnectAsync();
        await solidEdit.MoveBodyAsync(bodyIndex, dx, dy, dz);
        return await WithValidation($"Тело [{bodyIndex}] перемещено на ({dx}, {dy}, {dz}) мм.");
    }

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

    /// <summary>Дописать к сообщению результат проверки построения (операция могла «пройти», оставив ошибку).</summary>
    private async Task<string> WithValidation(string baseMsg)
    {
        var errs = await validation.ValidatePartAsync();
        if (errs.Count == 0) return baseMsg + " Построение чистое.";
        var lines = errs.Select(e => $"\"{e.Name}\" (код {e.ErrorCode}: {e.Description})");
        return baseMsg + $" ⚠ Внимание: {errs.Count} операц. в ошибке: " + string.Join("; ", lines) +
               ". Результат может быть некорректным.";
    }
}
