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

namespace GerbilManagerWebAPI.Endpoints
{
    /// <summary>
    /// WAITLIST (RennmausPro nachfrage_tb): a standing list of interested parties waiting
    /// for a future animal matching their wish criteria (colour, gender).
    ///   GET    /waiting-list           -> list entries, newest request first
    ///   POST   /waiting-list           -> create an entry (returns 201)
    ///   PUT    /waiting-list/{id}      -> update / change status
    ///   DELETE /waiting-list/{id}      -> remove an entry
    /// Decoupled from contacts (loose nullable ContactId, no FK), so rows survive the
    /// import re-ingest wipe — exactly like Feedback.
    /// </summary>
    public static class WaitingListEndpoints
    {
        /// <summary>Allowed workflow statuses (frontend contract).</summary>
        private static readonly string[] AllowedStatuses = { "offen", "erfuellt", "storniert" };
        private const string DefaultStatus = "offen";

        public static IEndpointRouteBuilder MapWaitingListEndpoints(this IEndpointRouteBuilder app)
        {
            var group = app.MapGroup("/waiting-list").WithTags("WaitingList");

            group.MapGet("/", async (ApplicationContext db) =>
            {
                // Order in memory: SQLite (test host) cannot ORDER BY a DateTimeOffset column,
                // and RequestedAt is nullable — sort entries with a date first, newest first.
                var rows = await db.WaitingListEntries.AsNoTracking().ToListAsync();
                return TypedResults.Ok(rows
                    .OrderByDescending(e => e.RequestedAt ?? DateTime.MinValue)
                    .ThenByDescending(e => e.CreatedAt)
                    .Select(ToDto)
                    .ToList());
            });

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

            group.MapPost("/", async Task<Results<Created<WaitingListDto>, BadRequest<string>>> (
                WaitingListInput input, ApplicationContext db) =>
            {
                var status = NormalizeStatus(input.Status);
                if (status is null)
                    return TypedResults.BadRequest("Ungültiger Status.");
                if (string.IsNullOrWhiteSpace(input.ContactName) && input.ContactId is null)
                    return TypedResults.BadRequest("Kontakt oder Name ist erforderlich.");

                var entity = new WaitingListEntry
                {
                    Id = Guid.NewGuid(),
                    ContactId = input.ContactId,
                    ContactName = Trim(input.ContactName),
                    WishColor = Trim(input.WishColor),
                    WishGender = Trim(input.WishGender),
                    RequestedAt = input.RequestedAt,
                    Status = status,
                    Note = Trim(input.Note),
                    CreatedAt = DateTimeOffset.UtcNow,
                };
                db.WaitingListEntries.Add(entity);
                await db.SaveChangesAsync();
                return TypedResults.Created($"/waiting-list/{entity.Id}", ToDto(entity));
            });

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

                var status = NormalizeStatus(input.Status);
                if (status is null)
                    return TypedResults.BadRequest("Ungültiger Status.");
                if (string.IsNullOrWhiteSpace(input.ContactName) && input.ContactId is null)
                    return TypedResults.BadRequest("Kontakt oder Name ist erforderlich.");

                entity.ContactId = input.ContactId;
                entity.ContactName = Trim(input.ContactName);
                entity.WishColor = Trim(input.WishColor);
                entity.WishGender = Trim(input.WishGender);
                entity.RequestedAt = input.RequestedAt;
                entity.Status = status;
                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.WaitingListEntries.FirstOrDefaultAsync(e => e.Id == id);
                if (entity is null) return TypedResults.NotFound();
                db.WaitingListEntries.Remove(entity);
                await db.SaveChangesAsync();
                return TypedResults.NoContent();
            });

            return app;
        }

        /// <summary>Empty/whitespace status defaults to "offen"; unknown values are rejected (null).</summary>
        private static string? NormalizeStatus(string? status)
        {
            if (string.IsNullOrWhiteSpace(status)) return DefaultStatus;
            var trimmed = status.Trim();
            return AllowedStatuses.Contains(trimmed) ? trimmed : null;
        }

        private static string? Trim(string? s) => string.IsNullOrWhiteSpace(s) ? null : s.Trim();

        private static WaitingListDto ToDto(WaitingListEntry e) =>
            new(e.Id, e.ContactId, e.ContactName, e.WishColor, e.WishGender, e.RequestedAt, e.Status, e.Note, e.CreatedAt);
    }
}
