using QuantEngine.Core.Interfaces;
using QuantEngine.Application.Services;

namespace QuantEngine.Web.Endpoints;

public static class CollectionEndpoints
{
    public static void MapCollectionEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("/api/collection")
            .WithName("Collection");

        group.MapGet("/state", GetCollectionState)
            .WithName("GetCollectionState")
            .Produces(200)
            .Produces(500);

        group.MapGet("/runs", GetRecentRuns)
            .WithName("GetRecentRuns")
            .Produces(200)
            .Produces(500);

        group.MapGet("/runs/{runId}/snapshots", GetRunSnapshots)
            .WithName("GetRunSnapshots")
            .Produces(200)
            .Produces(404)
            .Produces(500);

        group.MapGet("/runs/{runId}/errors", GetRunErrors)
            .WithName("GetRunErrors")
            .Produces(200)
            .Produces(404)
            .Produces(500);

        group.MapGet("/latest/{ticker}", GetLatestSnapshotsForTicker)
            .WithName("GetLatestSnapshotsForTicker")
            .Produces(200)
            .Produces(500);

        group.MapPost("/run", StartCollectionRun)
            .WithName("StartCollectionRun")
            .Produces(202)
            .Produces(500);
    }

    private static async Task<IResult> GetCollectionState(ICollectionRepository repo)
    {
        try
        {
            var state = await repo.GetDashboardStateAsync();
            return Results.Ok(state);
        }
        catch
        {
            return Results.StatusCode(500);
        }
    }

    private static async Task<IResult> GetRecentRuns(ICollectionRepository repo, int limit = 20)
    {
        try
        {
            var runs = await repo.GetRecentRunsAsync(limit);
            return Results.Ok(new { runs, count = runs.Count });
        }
        catch
        {
            return Results.StatusCode(500);
        }
    }

    private static async Task<IResult> GetRunSnapshots(string runId, ICollectionRepository repo)
    {
        try
        {
            var snapshots = await repo.GetRunSnapshotsAsync(runId);
            return Results.Ok(new { runId, snapshots, count = snapshots.Count });
        }
        catch
        {
            return Results.StatusCode(500);
        }
    }

    private static async Task<IResult> GetRunErrors(string runId, ICollectionRepository repo, int limit = 50)
    {
        try
        {
            var errors = await repo.GetRunErrorsAsync(runId, limit);
            return Results.Ok(new { runId, errors, count = errors.Count });
        }
        catch
        {
            return Results.StatusCode(500);
        }
    }

    private static async Task<IResult> GetLatestSnapshotsForTicker(string ticker, ICollectionRepository repo, int limit = 10)
    {
        try
        {
            var snapshots = await repo.GetLatestSnapshotsForTickerAsync(ticker, limit);
            return Results.Ok(new { ticker, snapshots, count = snapshots.Count });
        }
        catch
        {
            return Results.StatusCode(500);
        }
    }

    private static async Task<IResult> StartCollectionRun(
        DataCollectionService collectionService,
        HttpRequest request,
        ILogger<Program> logger)
    {
        try
        {
            var runId = Guid.NewGuid().ToString("N");
            var now = DateTime.UtcNow.ToString("o");

            var body = await request.ReadAsAsync<CollectionRunRequest>();
            var account = body?.Account ?? "real";
            var tickers = body?.Tickers ?? new List<string> { "005930", "000660" };

            // Trigger async collection (fire-and-forget)
            _ = Task.Run(async () =>
            {
                try
                {
                    await collectionService.RunCollectionAsync(runId, account, tickers);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "Collection run {RunId} failed", runId);
                }
            });

            return Results.Accepted($"/api/collection/runs/{runId}", new
            {
                runId,
                status = "running",
                startedAt = now,
                tickerCount = tickers.Count
            });
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to start collection run");
            return Results.StatusCode(500);
        }
    }

    private class CollectionRunRequest
    {
        public string? Account { get; set; }
        public List<string>? Tickers { get; set; }
    }
}
