using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Assemblies;
using Kompas.Mcp.Core.Conversion;
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Drawings;
using Kompas.Mcp.Core.Editing;
using Kompas.Mcp.Core.Interop;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
using Kompas.Mcp.Core.Startup;
using Kompas.Mcp.Core.Threading;
using Kompas.Mcp.Core.Validation;
using Kompas.Mcp.Core.Vision;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Protocol;

// Interop-сборки КОМПАС в поставку сервера не входят (принадлежат АСКОН) — они берутся из
// установленного КОМПАС-3D. Резолвер вешается до любых обращений к COM-типам; сам поиск ленивый,
// поэтому --version ниже работает и без установленного КОМПАС.
KompasInteropLoader.Install();

// Печать версии — до поднятия хоста: это не MCP-сессия, stdout свободен.
if (CliArguments.IsVersionRequest(args))
{
    var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
    Console.WriteLine(version?.ToString(3) ?? "0.0.0");
    return;
}

var builder = Host.CreateApplicationBuilder(args);

// ВАЖНО: stdout занят протоколом MCP (stdio). Все логи — только в stderr.
builder.Logging.AddConsole(o => o.LogToStandardErrorThreshold = LogLevel.Trace);
builder.Logging.SetMinimumLevel(LogLevel.Information);

// COM-слой: один STA-поток, одно подключение, общие сервисы (синглтоны).
builder.Services.AddSingleton<KompasDispatcher>();
builder.Services.AddSingleton<KompasSession>();
builder.Services.AddSingleton<DocumentService>();
builder.Services.AddSingleton<PartModeler>();
builder.Services.AddSingleton<HoleService>();
builder.Services.AddSingleton<PrimitiveService>();
builder.Services.AddSingleton<AssemblyService>();
builder.Services.AddSingleton<DrawingService>();
builder.Services.AddSingleton<VariableService>();
builder.Services.AddSingleton<SnapshotService>();
builder.Services.AddSingleton<QueryService>();
builder.Services.AddSingleton<ModelInspectionService>();
builder.Services.AddSingleton<ConversionService>();
builder.Services.AddSingleton<FaceEditService>();
builder.Services.AddSingleton<SolidEditService>();
builder.Services.AddSingleton<ValidationService>();
// Режим авто-валидации живёт на весь процесс: умолчание из KOMPAS_MCP_AUTOVALIDATE, переключение — set_auto_validate.
builder.Services.AddSingleton<AutoValidation>();

// MCP-сервер поверх stdio; инструменты находятся по атрибутам в этой сборке.
builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    // Без фильтра клиент получает на любую ошибку безликое «An error occurred invoking '<tool>'»:
    // SDK показывает текст исключения, только если оно McpException. А вся польза наших сообщений
    // именно в тексте («какого параметра не хватает», «почему операция не построилась»).
    .WithRequestFilters(filters => filters.AddCallToolFilter(next => async (context, ct) =>
    {
        try { return await next(context, ct); }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            return new CallToolResult
            {
                Content = [new TextContentBlock { Text = ToolErrorText.Describe(context.Params?.Name, ex) }],
                IsError = true,
            };
        }
    }))
    .WithToolsFromAssembly();

var app = builder.Build();

// Ранняя диагностика: поиск установки и распаковка сборок здесь, а не внутри первого вызова
// инструмента. Отсутствие сборок на старте не фатально — сообщение уйдёт в stderr, а падение
// случится там, где его увидит агент: на первом обращении к КОМПАС.
var interopLog = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Kompas.Interop");
try
{
    interopLog.LogInformation("Interop-сборки КОМПАС: {Directory}", KompasInteropLoader.ResolveDirectory());
}
catch (KompasInteropException ex)
{
    interopLog.LogWarning("{Message}", ex.Message);
}

await app.RunAsync();
