using System.Diagnostics;

namespace Hc900Crawler.Infrastructure.Mcp;

public class McpServerHostedService : IHostedService, IDisposable
{
    private readonly McpClient _mcpClient;
    private readonly ILogger<McpServerHostedService> _logger;
    private readonly string _workingDirectory;
    private Process? _process;

    public McpServerHostedService(
        McpClient mcpClient,
        ILogger<McpServerHostedService> logger,
        IConfiguration config)
    {
        _mcpClient = mcpClient;
        _logger = logger;
        var dir = config["McpServer:WorkingDirectory"] ?? "../../mcp-server";
        _workingDirectory = Path.IsPathRooted(dir)
            ? dir
            : Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), dir));
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (!Directory.Exists(_workingDirectory))
        {
            _logger.LogWarning("[McpServer] 디렉터리 없음: {Dir} — MCP 서버 시작 스킵", _workingDirectory);
        }
        else
        {
            // 이미 MCP 서버가 실행 중이면 시작하지 않음
            if (await _mcpClient.PingAsync())
            {
                _logger.LogInformation("[McpServer] 이미 실행 중 (localhost:5001) — 기존 프로세스 사용");
                return;
            }
            else
            {
                _logger.LogInformation("[McpServer] Python MCP 서버 시작 중... ({Dir})", _workingDirectory);

                _process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "uv",
                        Arguments = "run server.py --http",
                        WorkingDirectory = _workingDirectory,
                        UseShellExecute = false,
                    }
                };

                try
                {
                    _process.Start();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "[McpServer] 프로세스 시작 실패 (uv 설치 여부 확인)");
                }

                // MCP 서버가 포트를 bind하기 위해 약간 대기 (0.5초)
                await Task.Delay(500, cancellationToken);

                // 최대 30초 대기 (1초 간격 health check)
                for (int i = 0; i < 30; i++)
                {
                    try { await Task.Delay(1000, cancellationToken); } catch { return; }
                    if (_process.HasExited)
                    {
                        _logger.LogWarning("[McpServer] 프로세스가 예기치 않게 종료됨 (exit code: {Code})", _process.ExitCode);
                        return;
                    }
                    if (await _mcpClient.PingAsync())
                    {
                        _logger.LogInformation("[McpServer] 준비 완료 (localhost:5001, {Sec}초 소요)", i + 1);
                        return;
                    }
                }
                _logger.LogWarning("[McpServer] 30초 내 응답 없음 — 백그라운드에서 계속 기다림");
            }
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        if (_process != null && !_process.HasExited)
        {
            try
            {
                _logger.LogInformation("[McpServer] 앱 종료 — MCP 서버 프로세스 종료 중...");
                _process.Kill(entireProcessTree: true);
            }
            catch (Exception ex) { _logger.LogWarning(ex, "[McpServer] 프로세스 종료 중 오류"); }
        }
        _logger.LogInformation("[McpServer] 앱 종료 완료");
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        try { _process?.Dispose(); }
        catch (Exception ex) { _logger.LogDebug(ex, "[McpServer] Process Dispose 예외 (무시)"); }
        _process = null;
        GC.SuppressFinalize(this);
    }
}
