using System.ComponentModel;
using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Modeling;
using ModelContextProtocol.Server;

namespace Kompas.Mcp.Host.Tools;

/// <summary>Инструменты эскиза: создание на плоскости/грани и наполнение примитивами.</summary>
[McpServerToolType]
public sealed class SketchTools(KompasSession session, PartModeler modeler)
{
    [McpServerTool(Name = "sketch_create")]
    [Description("Создать эскиз активной детали и (при передаче entities) сразу построить в нём геометрию — " +
                 "весь контур одним вызовом. Основание эскиза задаётся ОДНИМ из способов: plane (базовая " +
                 "плоскость XOY|XOZ|YOZ, при offset≠0 — смещённая от неё на offset мм); faceIndex (грань из " +
                 "list_faces — предпочтительный способ строить «на грани» уже созданного тела); либо точка x,y,z " +
                 "на грани в мировых координатах модели (запасной вариант, когда индекс не подходит). " +
                 "entities — список примитивов, autoClose=true закрывает эскиз сразу, чтобы можно было звать " +
                 "extrude/revolve. Без entities эскиз остаётся открытым — наполняйте его через sketch_add. " +
                 "name — имя эскиза в дереве построения («Контур плашки»): давайте его ВСЕГДА, иначе дерево " +
                 "состоит из безликих «Эскиз:1…N» и по нему нельзя понять, что где. Возвращает id эскиза.")]
    public async Task<string> Create(
        [Description("Базовая плоскость: XOY | XOZ | YOZ")] string? plane = null,
        [Description("Индекс грани из list_faces (надёжнее выбора по точке)")] int? faceIndex = null,
        [Description("X точки на грани, мировые координаты модели, мм")] double? x = null,
        [Description("Y точки на грани, мм")] double? y = null,
        [Description("Z точки на грани, мм")] double? z = null,
        [Description("Смещение от базовой плоскости, мм (только вместе с plane)")] double offset = 0,
        [Description("Прямое направление смещения от базовой плоскости")] bool offsetDirection = true,
        [Description("Примитивы эскиза: список объектов {type, points, centerX, ...}")] SketchEntityInput[]? entities = null,
        [Description("Закрыть эскиз после построения entities (нужно перед операцией)")] bool autoClose = true,
        [Description("Имя эскиза в дереве построения, например «Контур плашки»")] string? name = null)
    {
        await session.ConnectAsync();
        var parsed = SketchEntityInputs.Parse(entities);

        int id;
        string on;
        if (faceIndex is { } fi)
        {
            id = await modeler.OpenSketchOnFaceIndexAsync(fi, name);
            on = $"грани [{fi}]";
        }
        else if (x is { } px && y is { } py && z is { } pz)
        {
            id = await modeler.OpenSketchOnFaceAsync(px, py, pz, name);
            on = $"грани в точке ({px}, {py}, {pz})";
        }
        else if (!string.IsNullOrWhiteSpace(plane))
        {
            var basePlane = BasePlanes.Parse(plane);
            if (offset == 0)
            {
                id = await modeler.OpenSketchAsync(basePlane, name);
                on = $"плоскости {plane}";
            }
            else
            {
                id = await modeler.OpenSketchOnOffsetPlaneAsync(basePlane, offset, offsetDirection, name);
                on = $"плоскости {plane}, смещение {offset} мм";
            }
        }
        else
        {
            throw new ArgumentException(
                "Не задано основание эскиза: передайте plane (XOY|XOZ|YOZ), либо faceIndex из list_faces, " +
                "либо все три координаты точки на грани (x, y, z).");
        }

        if (parsed.Count == 0)
            return $"Эскиз id={id} создан на {on} и открыт. Добавьте геометрию через sketch_add.";

        // Пакет строится за один заход на COM-поток; autoClose закрывает эскиз там же.
        var notes = await modeler.AddEntitiesAsync(id, parsed, autoClose);
        var state = autoClose ? "закрыт — можно строить операцию" : "остался открытым";
        return $"Эскиз id={id} создан на {on}, добавлено примитивов: {parsed.Count}, {state}.{Notes(notes)}";
    }

    [McpServerTool(Name = "sketch_add")]
    [Description("Добавить примитивы в ОТКРЫТЫЙ эскиз (id из sketch_create) — список за один вызов. " +
                 "Нужен, когда эскиз наполняется в несколько приёмов; если геометрия известна сразу, " +
                 "передавайте её прямо в sketch_create. autoClose=true завершает эскиз после добавления. " +
                 "Каждый элемент entities: {type, points, centerX, centerY, radius, ...} — обязательные поля " +
                 "зависят от type.")]
    public async Task<string> Add(
        [Description("Id эскиза из sketch_create")] int sketchId,
        [Description("Примитивы эскиза: список объектов {type, points, centerX, ...}")] SketchEntityInput[] entities,
        [Description("Закрыть эскиз после добавления")] bool autoClose = false)
    {
        await session.ConnectAsync();
        var parsed = SketchEntityInputs.Parse(entities);
        if (parsed.Count == 0)
            throw new ArgumentException("Список entities пуст — нечего добавлять.");

        var notes = await modeler.AddEntitiesAsync(sketchId, parsed, autoClose);
        var state = autoClose ? " Эскиз закрыт." : "";
        return $"В эскиз id={sketchId} добавлено примитивов: {parsed.Count}.{state}{Notes(notes)}";
    }

    /// <summary>Заметки по построенным примитивам (сейчас — метрики надписей: габарит глифов и ячейка).</summary>
    private static string Notes(IReadOnlyList<string> notes)
    {
        var meaningful = notes.Where(n => !string.IsNullOrEmpty(n)).ToList();
        return meaningful.Count == 0 ? "" : " " + string.Join("; ", meaningful) + ".";
    }

    [McpServerTool(Name = "sketch_close")]
    [Description("Завершить редактирование эскиза. Нужен, только если эскиз наполнялся с autoClose=false — " +
                 "перед формообразующей операцией эскиз должен быть закрыт.")]
    public async Task<string> Close(int sketchId)
    {
        await session.ConnectAsync();
        await modeler.CloseSketchAsync(sketchId);
        return $"Эскиз id={sketchId} закрыт.";
    }
}
