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

namespace GerbilManagerWebAPI.Endpoints
{
    public static class ContactEndpoints
    {
        public static IEndpointRouteBuilder MapContactEndpoints(this IEndpointRouteBuilder app)
        {
            var group = app.MapGroup("/contacts").WithTags("Contacts");

            group.MapGet("/", async ([AsParameters] GridifyParams query, ApplicationContext db) =>
                TypedResults.Ok(await db.Contacts.AsNoTracking().ToPagedResultAsync(query, ToDto)));

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

            group.MapPost("/", async (ContactInput input, ApplicationContext db) =>
            {
                var c = new Contact { Id = Guid.NewGuid(), Name = input.Name, Email = input.Email, Phone = input.Phone, Address = input.Address, Notes = input.Notes };
                db.Contacts.Add(c);
                await db.SaveChangesAsync();
                return TypedResults.Created($"/contacts/{c.Id}", ToDto(c));
            });

            group.MapPut("/{id:guid}", async Task<Results<NoContent, NotFound>> (Guid id, ContactInput input, ApplicationContext db) =>
            {
                var c = await db.Contacts.FirstOrDefaultAsync(x => x.Id == id);
                if (c is null) return TypedResults.NotFound();
                c.Name = input.Name; c.Email = input.Email; c.Phone = input.Phone; c.Address = input.Address; c.Notes = input.Notes;
                await db.SaveChangesAsync();
                return TypedResults.NoContent();
            });

            // 409 if any gerbil references this contact as origin or receiver.
            group.MapDelete("/{id:guid}", async Task<Results<NoContent, NotFound, Conflict<string>>> (Guid id, ApplicationContext db) =>
            {
                var c = await db.Contacts.FirstOrDefaultAsync(x => x.Id == id);
                if (c is null) return TypedResults.NotFound();
                bool linked = await db.Gerbils.AnyAsync(g => g.OriginContactId == id || g.ReceiverContactId == id);
                if (linked) return TypedResults.Conflict("Contact is linked to one or more gerbils and cannot be deleted.");
                db.Contacts.Remove(c);
                await db.SaveChangesAsync();
                return TypedResults.NoContent();
            });

            return app;
        }

        private static ContactDto ToDto(Contact c) => new(c.Id, c.Name, c.Email, c.Phone, c.Address, c.Notes);
    }
}
