using LiteCqrs;
using TeleWave.Api.Common;
using TeleWave.Application.Metadata;
using TeleWave.Application.Metadata.ApplyShowMetadata;
using TeleWave.Application.Metadata.ClearShowMetadata;
using TeleWave.Application.Metadata.FindMissingEpisodes;
using TeleWave.Application.Metadata.FindMissingSeasons;
using TeleWave.Application.Metadata.GetProviders;
using TeleWave.Application.Metadata.RefreshEpisodes;
using TeleWave.Application.Metadata.SearchShows;
using TeleWave.Application.Metadata.SetShowPoster;
using TeleWave.Application.Metadata.UpdateShowMetadata;
using TeleWave.Domain.Library;
using TeleWave.Infrastructure.Identity;

namespace TeleWave.Api.Endpoints;

public static class MetadataEndpoints
{
    public static IEndpointRouteBuilder MapMetadataEndpoints(this IEndpointRouteBuilder app)
    {
        var admin = app.MapGroup("/api/admin/metadata")
            .WithTags("Admin.Metadata")
            .RequireAuthorization(policy => policy.RequireRole(RoleNames.Admin));

        admin.MapGet("/providers", GetProviders).Produces<IReadOnlyList<string>>();
        admin.MapGet("/search", Search).Produces<IReadOnlyList<MetadataCandidate>>();
        admin.MapPost("/shows/{showId:guid}/apply", Apply).Produces(StatusCodes.Status204NoContent);
        admin.MapPut("/shows/{showId:guid}", Update).Produces(StatusCodes.Status204NoContent);
        admin.MapDelete("/shows/{showId:guid}", Clear).Produces(StatusCodes.Status204NoContent);
        admin
            .MapPut("/shows/{showId:guid}/poster-image", SetPosterImage)
            .Produces(StatusCodes.Status204NoContent);
        admin.MapPost("/shows/{showId:guid}/refresh-episodes", RefreshEpisodes).Produces<int>();
        admin
            .MapGet("/shows/{showId:guid}/missing-episodes", FindMissing)
            .Produces<MissingEpisodesReport>();
        admin
            .MapGet("/shows/{showId:guid}/missing-seasons", FindMissingSeasons)
            .Produces<MissingSeasonsReport>();

        // Постеры шоу и кадры серий теперь в общем реестре и отдаются по /api/images/{id}.
        return app;
    }

    private static async Task<IResult> GetProviders(
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var providers = await sender.Send(new GetMetadataProvidersQuery(), cancellationToken);
        return Results.Ok(providers);
    }

    private static async Task<IResult> Search(
        string provider,
        string query,
        ShowKind kind,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new SearchShowMetadataQuery(provider, query, kind),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> Apply(
        Guid showId,
        ApplyMetadataBody body,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new ApplyShowMetadataCommand(showId, body.Provider, body.ExternalId),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> Update(
        Guid showId,
        UpdateMetadataBody body,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new UpdateShowMetadataCommand(showId, body.Description, body.Year),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> Clear(
        Guid showId,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(new ClearShowMetadataCommand(showId), cancellationToken);
        return result.ToHttpResult();
    }

    private static async Task<IResult> SetPosterImage(
        Guid showId,
        SetPosterImageBody body,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new SetShowPosterCommand(showId, body.ImageId),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> RefreshEpisodes(
        Guid showId,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(
            new RefreshShowEpisodesMetadataCommand(showId),
            cancellationToken
        );
        return result.ToHttpResult();
    }

    private static async Task<IResult> FindMissing(
        Guid showId,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(new FindMissingEpisodesQuery(showId), cancellationToken);
        return result.ToHttpResult();
    }

    private static async Task<IResult> FindMissingSeasons(
        Guid showId,
        ISender sender,
        CancellationToken cancellationToken
    )
    {
        var result = await sender.Send(new FindMissingSeasonsQuery(showId), cancellationToken);
        return result.ToHttpResult();
    }
}

public sealed record ApplyMetadataBody(string Provider, string ExternalId);

public sealed record UpdateMetadataBody(string? Description, int? Year);

public sealed record SetPosterImageBody(Guid? ImageId);
