using GerbilManagerWebAPI.Dtos;
using GerbilManagerWebAPI.Models;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.EntityFrameworkCore;

namespace GerbilManagerWebAPI.Endpoints
{
    /// <summary>
    /// EXHIBITION: show/exhibition results &amp; awards per animal (RennmausPro `ausz_tb`).
    ///   GET    /exhibitions[?gerbilId=…] -> list (optionally filtered to one animal), newest first.
    ///   POST   /exhibitions              -> create a result, returns 201.
    ///   PUT    /exhibitions/{id}         -> edit a result (partial), 404 on missing id.
    ///   DELETE /exhibitions/{id}         -> remove a result, 404 on missing id.
    /// Decoupled from gerbils (loose nullable GerbilId, no FK) so rows survive the import re-ingest wipe.
    /// </summary>
    public static class ExhibitionEndpoints
    {
        public static IEndpointRouteBuilder MapExhibitionEndpoints(this IEndpointRouteBuilder app)
        {
            var group = app.MapGroup("/exhibitions").WithTags("Exhibitions");

            group.MapGet("/", async (ApplicationContext db, Guid? gerbilId) =>
            {
                // Filter in the query; order in memory (SQLite test host cannot ORDER BY a
                // DateTimeOffset column — mirrors FeedbackEndpoints).
                var query = db.ExhibitionResults.AsNoTracking();
                if (gerbilId is { } gid)
                    query = query.Where(x => x.GerbilId == gid);
                var rows = await query.ToListAsync();
                return TypedResults.Ok(rows
                    .OrderByDescending(x => x.Date ?? DateTime.MinValue)
                    .ThenByDescending(x => x.CreatedAt)
                    .Select(ToDto)
                    .ToList());
            });

            group.MapGet("/{id:guid}", async Task<Results<Ok<ExhibitionResultDto>, NotFound>> (
                Guid id, ApplicationContext db) =>
            {
                var r = await db.ExhibitionResults.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
                return r is null ? TypedResults.NotFound() : TypedResults.Ok(ToDto(r));
            });

            group.MapPost("/", async Task<Results<Created<ExhibitionResultDto>, BadRequest<string>>> (
                ExhibitionResultInput input, ApplicationContext db) =>
            {
                if (string.IsNullOrWhiteSpace(input.EventName))
                    return TypedResults.BadRequest("EventName darf nicht leer sein.");

                var entity = new ExhibitionResult
                {
                    Id = Guid.NewGuid(),
                    GerbilId = input.GerbilId,
                    EntityName = Trim(input.EntityName),
                    EventName = input.EventName.Trim(),
                    Date = input.Date,
                    Placement = Trim(input.Placement),
                    Award = Trim(input.Award),
                    Note = Trim(input.Note),
                    CreatedAt = DateTimeOffset.UtcNow,
                };
                db.ExhibitionResults.Add(entity);
                await db.SaveChangesAsync();
                return TypedResults.Created($"/exhibitions/{entity.Id}", ToDto(entity));
            });

            group.MapPut("/{id:guid}", async Task<Results<Ok<ExhibitionResultDto>, NotFound, BadRequest<string>>> (
                Guid id, ExhibitionResultUpdate input, ApplicationContext db) =>
            {
                var entity = await db.ExhibitionResults.FirstOrDefaultAsync(x => x.Id == id);
                if (entity is null)
                    return TypedResults.NotFound();

                if (input.EventName is not null)
                {
                    if (string.IsNullOrWhiteSpace(input.EventName))
                        return TypedResults.BadRequest("EventName darf nicht leer sein.");
                    entity.EventName = input.EventName.Trim();
                }
                if (input.GerbilId is not null) entity.GerbilId = input.GerbilId;
                if (input.EntityName is not null) entity.EntityName = Trim(input.EntityName);
                if (input.Date is not null) entity.Date = input.Date;
                if (input.Placement is not null) entity.Placement = Trim(input.Placement);
                if (input.Award is not null) entity.Award = Trim(input.Award);
                if (input.Note is not null) entity.Note = Trim(input.Note);

                await db.SaveChangesAsync();
                return TypedResults.Ok(ToDto(entity));
            });

            group.MapDelete("/{id:guid}", async Task<Results<NoContent, NotFound>> (
                Guid id, ApplicationContext db) =>
            {
                var entity = await db.ExhibitionResults.FirstOrDefaultAsync(x => x.Id == id);
                if (entity is null)
                    return TypedResults.NotFound();

                db.ExhibitionResults.Remove(entity);
                await db.SaveChangesAsync();
                return TypedResults.NoContent();
            });

            return app;
        }

        // Empty/whitespace optional strings normalise to null.
        private static string? Trim(string? s) =>
            string.IsNullOrWhiteSpace(s) ? null : s.Trim();

        private static ExhibitionResultDto ToDto(ExhibitionResult r) =>
            new(r.Id, r.GerbilId, r.EntityName, r.EventName, r.Date,
                r.Placement, r.Award, r.Note, r.CreatedAt);
    }
}
