using Microsoft.AspNetCore.Mvc;
using Hc900Crawler.Core.Application.DTOs;
using Hc900Crawler.Core.Application.Services;
using System.Net.Http.Json;
using System.Collections.Concurrent;

using Hc900Crawler.Core.Application.Interfaces;

namespace Hc900Crawler.Web.Controllers;

[ApiController]
[Route("api/[controller]")]
public class PidGraphController : ControllerBase
{
    private readonly IPidGraphService _pidGraphService;
    private readonly ILogger<PidGraphController> _logger;
    private readonly IStatusStore _statusStore;
    private readonly IPidGraphEventBroadcaster _eventBroadcaster;

    public PidGraphController(IPidGraphService pidGraphService, ILogger<PidGraphController> logger, IStatusStore statusStore, IPidGraphEventBroadcaster eventBroadcaster)
    {
        _pidGraphService = pidGraphService;
        _logger = logger;
        _statusStore = statusStore;
        _eventBroadcaster = eventBroadcaster;
    }

    [HttpGet("impact/{graphId}/{nodeId}")]
    public async Task<IActionResult> GetImpactAnalysis(string graphId, string nodeId, CancellationToken ct)
    {
        try
        {
            _logger.LogInformation("Requesting impact analysis for graph: {GraphId}, node: {NodeId}", graphId, nodeId);
            
            var result = await _pidGraphService.AnalyzeImpactAsync(graphId, nodeId, ct);
            
            if (!result.Success)
            {
                return NotFound(PidResponse<object>.Fail(result.Error ?? "Unknown error"));
            }
            
            // 프론트엔드 camelCase 규칙 준수 및 PidResponse 래핑
            return Ok(new
            {
                success = true,
                data = new
                {
                    startNode = result.StartNode,
                    impactedNodes = result.ImpactedNodes,
                    paths = result.Paths
                },
                message = "분석 완료"
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unexpected error during impact analysis");
            return StatusCode(500, new { error = "Internal server error", details = ex.Message });
        }
    }

    [HttpGet("status/{taskId}")]
    public async Task<IActionResult> GetAnalysisStatus(string taskId)
    {
        var status = await _statusStore.GetStatusAsync(taskId);
        if (status != null)
        {
            return Ok(new
            {
                success = true,
                data = new
                {
                    taskId = status.TaskId,
                    progress = status.Progress,
                    status = status.Status,
                    message = status.Message
                }
            });
        }
        return NotFound();
    }

    [HttpGet("status/stream/{taskId}")]
    public async Task GetAnalysisStatusStream(string taskId, CancellationToken ct)
    {
        Response.ContentType = "text/event-stream";
        Response.Headers.Append("Cache-Control", "no-cache");
        Response.Headers.Append("Connection", "keep-alive");

        _logger.LogInformation("SSE stream started for taskId: {TaskId}", taskId);

        try
        {
            await foreach (var status in _eventBroadcaster.SubscribeAsync(taskId, ct))
            {
                var data = System.Text.Json.JsonSerializer.Serialize(new
                {
                    taskId = status.TaskId,
                    progress = status.Progress,
                    status = status.Status,
                    message = status.Message
                });

                await Response.WriteAsync($"data: {data}\n\n", ct);
                await Response.Body.FlushAsync(ct);
            }
        }
        catch (OperationCanceledException)
        {
            _logger.LogInformation("SSE stream cancelled for taskId: {TaskId}", taskId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error in SSE stream for taskId: {TaskId}", taskId);
        }
    }

    // 그래프 생성 API
    [HttpPost("build")]
    public async Task<IActionResult> BuildGraph([FromBody] BuildGraphRequest request)
    {
        if (string.IsNullOrEmpty(request.Filepath))
            return BadRequest(new { error = "Filepath is required" });

        var taskId = Guid.NewGuid().ToString();
        await _statusStore.UpdateStatusAsync(new AnalysisStatus(taskId, 0, "Starting", "추출 준비 중..."));

        // 백그라운드 작업으로 실행하여 taskId 즉시 반환
        // IHostApplicationLifetime을 주입받아 앱 종료 시 취소 가능하도록 설정
        var lifetime = HttpContext.RequestServices.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
        var cts = new CancellationTokenSource();
        
        // 앱 종료 시 cts 취소 등록
        lifetime.ApplicationStopping.Register(() => cts.Cancel());

        _ = Task.Run(async () =>
        {
            try
            {
                await _statusStore.UpdateStatusAsync(new AnalysisStatus(taskId, 10, "Processing", "도면 기하학적 데이터 추출 중..."));
                
                var result = await _pidGraphService.BuildPidGraphAsync(request.Filepath, async (progress, msg) =>
                {
                    var status = new AnalysisStatus(taskId, progress, "Processing", msg);
                    await _statusStore.UpdateStatusAsync(status);
                    await _eventBroadcaster.NotifyAsync(taskId, status);
                }, cts.Token);

                if (result.Success)
                {
                    var status = new AnalysisStatus(taskId, 100, "Completed", "추출 완료");
                    await _statusStore.UpdateStatusAsync(status);
                    await _eventBroadcaster.NotifyAsync(taskId, status);
                }
                else
                {
                    var status = new AnalysisStatus(taskId, 0, "Failed", result.Error ?? "Unknown error");
                    await _statusStore.UpdateStatusAsync(status);
                    await _eventBroadcaster.NotifyAsync(taskId, status);
                }
            }
            catch (OperationCanceledException)
            {
                _logger.LogInformation("Background graph build task {TaskId} was cancelled due to application shutdown", taskId);
                var status = new AnalysisStatus(taskId, 0, "Cancelled", "애플리케이션 종료로 인해 작업이 취소되었습니다.");
                await _statusStore.UpdateStatusAsync(status);
                await _eventBroadcaster.NotifyAsync(taskId, status);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Background graph build error for task {TaskId}", taskId);
                var status = new AnalysisStatus(taskId, 0, "Failed", ex.Message);
                await _statusStore.UpdateStatusAsync(status);
                await _eventBroadcaster.NotifyAsync(taskId, status);
            }
            finally
            {
                cts.Dispose();
            }
        });

        return Ok(new
        {
            success = true,
            data = new { taskId = taskId },
            message = "작업이 시작되었습니다."
        });
    }

    public record BuildGraphRequest(string Filepath);
}
