using FastEndpoints;
using Hangfire;
using QuantEngine.Application.Interfaces;
using QuantEngine.Core.Interfaces;

namespace QuantEngine.Web.Endpoints;

public class GetCollectionStateEndpoint : EndpointWithoutRequest<CollectionDashboardStateRecord>
{
    private readonly ICollectionReadModelService _readModelService;

    public GetCollectionStateEndpoint(ICollectionReadModelService readModelService)
    {
        _readModelService = readModelService;
    }

    public override void Configure()
    {
        Get("/api/collection/state");
        AllowAnonymous();
        Description(d => d
            .Produces<CollectionDashboardStateRecord>(200)
            .Produces(500));
    }

    public override async Task HandleAsync(CancellationToken ct)
    {
        try
        {
            var state = await _readModelService.GetDashboardStateAsync();
            await SendOkAsync(state, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}

public class GetRecentRunsRequest
{
    public int Limit { get; set; } = 20;
}

public class GetRecentRunsResponse
{
    public List<CollectionRunRecord> Runs { get; set; } = new();
    public int Count { get; set; }
}

public class GetRecentRunsEndpoint : Endpoint<GetRecentRunsRequest, GetRecentRunsResponse>
{
    private readonly ICollectionReadModelService _readModelService;

    public GetRecentRunsEndpoint(ICollectionReadModelService readModelService)
    {
        _readModelService = readModelService;
    }

    public override void Configure()
    {
        Get("/api/collection/runs");
        AllowAnonymous();
        Description(d => d
            .Produces<GetRecentRunsResponse>(200)
            .Produces(500));
    }

    public override async Task HandleAsync(GetRecentRunsRequest req, CancellationToken ct)
    {
        try
        {
            var runs = await _readModelService.GetRecentRunsAsync(req.Limit);
            await SendOkAsync(new GetRecentRunsResponse { Runs = runs, Count = runs.Count }, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}

public class GetRunSnapshotsRequest
{
    public string RunId { get; set; } = "";
}

public class GetRunSnapshotsResponse
{
    public string RunId { get; set; } = "";
    public List<CollectionSnapshotRecord> Snapshots { get; set; } = new();
    public int Count { get; set; }
}

public class GetRunSnapshotsEndpoint : Endpoint<GetRunSnapshotsRequest, GetRunSnapshotsResponse>
{
    private readonly ICollectionReadModelService _readModelService;

    public GetRunSnapshotsEndpoint(ICollectionReadModelService readModelService)
    {
        _readModelService = readModelService;
    }

    public override void Configure()
    {
        Get("/api/collection/runs/{RunId}/snapshots");
        AllowAnonymous();
        Description(d => d
            .Produces<GetRunSnapshotsResponse>(200)
            .Produces(404)
            .Produces(500));
    }

    public override async Task HandleAsync(GetRunSnapshotsRequest req, CancellationToken ct)
    {
        try
        {
            var snapshots = await _readModelService.GetRunSnapshotsAsync(req.RunId);
            await SendOkAsync(new GetRunSnapshotsResponse { RunId = req.RunId, Snapshots = snapshots, Count = snapshots.Count }, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}

public class GetRunErrorsRequest
{
    public string RunId { get; set; } = "";
    public int Limit { get; set; } = 50;
}

public class GetRunErrorsResponse
{
    public string RunId { get; set; } = "";
    public List<CollectionErrorRecord> Errors { get; set; } = new();
    public int Count { get; set; }
}

public class GetRunErrorsEndpoint : Endpoint<GetRunErrorsRequest, GetRunErrorsResponse>
{
    private readonly ICollectionReadModelService _readModelService;

    public GetRunErrorsEndpoint(ICollectionReadModelService readModelService)
    {
        _readModelService = readModelService;
    }

    public override void Configure()
    {
        Get("/api/collection/runs/{RunId}/errors");
        AllowAnonymous();
        Description(d => d
            .Produces<GetRunErrorsResponse>(200)
            .Produces(404)
            .Produces(500));
    }

    public override async Task HandleAsync(GetRunErrorsRequest req, CancellationToken ct)
    {
        try
        {
            var errors = await _readModelService.GetRunErrorsAsync(req.RunId, req.Limit);
            await SendOkAsync(new GetRunErrorsResponse { RunId = req.RunId, Errors = errors, Count = errors.Count }, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}

public class GetLatestSnapshotsRequest
{
    public string Ticker { get; set; } = "";
    public int Limit { get; set; } = 10;
}

public class GetLatestSnapshotsResponse
{
    public string Ticker { get; set; } = "";
    public List<CollectionSnapshotRecord> Snapshots { get; set; } = new();
    public int Count { get; set; }
}

public class GetLatestSnapshotsEndpoint : Endpoint<GetLatestSnapshotsRequest, GetLatestSnapshotsResponse>
{
    private readonly ICollectionReadModelService _readModelService;

    public GetLatestSnapshotsEndpoint(ICollectionReadModelService readModelService)
    {
        _readModelService = readModelService;
    }

    public override void Configure()
    {
        Get("/api/collection/latest/{Ticker}");
        AllowAnonymous();
        Description(d => d
            .Produces<GetLatestSnapshotsResponse>(200)
            .Produces(500));
    }

    public override async Task HandleAsync(GetLatestSnapshotsRequest req, CancellationToken ct)
    {
        try
        {
            var snapshots = await _readModelService.GetLatestSnapshotsForTickerAsync(req.Ticker, req.Limit);
            await SendOkAsync(new GetLatestSnapshotsResponse { Ticker = req.Ticker, Snapshots = snapshots, Count = snapshots.Count }, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}

public class GetPriceHistorySummaryResponse
{
    public List<PriceHistorySummaryRecord> Tickers { get; set; } = new();
}

public class GetPriceHistorySummaryEndpoint : EndpointWithoutRequest<GetPriceHistorySummaryResponse>
{
    private readonly ICollectionReadModelService _readModelService;
    private readonly ILogger<GetPriceHistorySummaryEndpoint> _logger;

    public GetPriceHistorySummaryEndpoint(ICollectionReadModelService readModelService, ILogger<GetPriceHistorySummaryEndpoint> logger)
    {
        _readModelService = readModelService;
        _logger = logger;
    }

    public override void Configure()
    {
        Get("/api/collection/history-summary");
        AllowAnonymous();
        Description(d => d
            .Produces<GetPriceHistorySummaryResponse>(200)
            .Produces(500));
    }

    public override async Task HandleAsync(CancellationToken ct)
    {
        try
        {
            var summary = await _readModelService.GetPriceHistorySummaryAsync();
            await SendOkAsync(new GetPriceHistorySummaryResponse { Tickers = summary }, ct);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to fetch price history summary");
            await SendErrorsAsync(500, ct);
        }
    }
}

public class StartCollectionRunResponse
{
    public string RunId { get; set; } = "";
}

public class StartCollectionRunEndpoint : EndpointWithoutRequest<StartCollectionRunResponse>
{
    private readonly IBackgroundJobClient _jobClient;
    private readonly IConfiguration _configuration;
    private readonly ILogger<StartCollectionRunEndpoint> _logger;

    public StartCollectionRunEndpoint(
        IBackgroundJobClient jobClient,
        IConfiguration configuration,
        ILogger<StartCollectionRunEndpoint> logger)
    {
        _jobClient = jobClient;
        _configuration = configuration;
        _logger = logger;
    }

    public override void Configure()
    {
        Post("/api/collection/run");
        Description(d => d
            .Produces<StartCollectionRunResponse>(202)
            .Produces(500));
    }

    public override async Task HandleAsync(CancellationToken ct)
    {
        try
        {
            var runId = $"api-{DateTime.Now:yyyyMMdd-HHmmss}";
            var accountMode = _configuration["Kis:AccountMode"] ?? "mock";
            var tickers = new[] { "005930", "000660", "051910", "005380", "010140", "005490" }.ToList();

            _jobClient.Enqueue<ICollectionOrchestrator>(o => o.RunCollectionAsync(runId, accountMode, tickers));

            _logger.LogInformation("Collection run {RunId} enqueued", runId);

            await SendAsync(new StartCollectionRunResponse { RunId = runId }, 202, ct);
        }
        catch
        {
            await SendErrorsAsync(500, ct);
        }
    }
}
