using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;

namespace Guestlist.Components.Pages;

public partial class Guests : ComponentBase
{
    [Inject]
    protected GuestEntryService GuestEntryService { get; set; } = default!;

    [Inject]
    protected AuthenticationStateProvider AuthenticationStateProvider { get; set; } = default!;
    
    protected string NewGuestName { get; set; } = "";
    protected string NewGuestNotes { get; set; } = "";
    protected string ErrorMessage { get; set; } = "";
    protected string SearchTerm { get; set; } = "";
    
    protected string? EditingGuestId { get; set; }
    protected string EditGuestName { get; set; } = "";
    protected string EditGuestNotes { get; set; } = "";
    
    protected List<GuestEntryDocument>? GuestEntries { get; set; }

    [SupplyParameterFromQuery(Name = "error")]
    public string? IncomingError { get; set; }

    [SupplyParameterFromQuery(Name = "search")]
    public string? IncomingSearchTerm { get; set; }

    [SupplyParameterFromQuery(Name = "edit")]
    public string? IncomingEditingGuestId { get; set; }

    protected IEnumerable<GuestEntryDocument> FilteredGuestEntries
    {
        get
        {
            if (GuestEntries is null)
            {
                return [];
            }

            if (string.IsNullOrWhiteSpace(SearchTerm))
            {
                return GuestEntries;
            }

            var searchTerm = SearchTerm.Trim();

            return GuestEntries.Where(guest =>
                guest.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) ||
                (guest.Notes?.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) == true) ||
                guest.AddedByUsername.Contains(searchTerm, StringComparison.OrdinalIgnoreCase));
        }
    }

    protected override async Task OnInitializedAsync()
    {
        SearchTerm = IncomingSearchTerm ?? "";
        EditingGuestId = IncomingEditingGuestId;

        ErrorMessage = IncomingError switch
        {
            "duplicate" => "A guest with this name and note already exists. Use a distinct note if this is a different person.",
            "add-failed" => "Guest could not be added.",
            null or "" => "",
            _ => IncomingError
        };

        try
        {
            GuestEntries = await GuestEntryService.GetAllAsync();
        }
        catch
        {
            ErrorMessage = "Guest list could not be loaded.";
            GuestEntries = [];
        }
    }
    
    protected async Task AddGuest()
    {
        ErrorMessage = "";

        if (string.IsNullOrWhiteSpace(NewGuestName))
        {
            ErrorMessage = "Provide a guest name.";
            return;
        }

        try
        {
            if (await GuestEntryService.NameAndNotesExistAsync(NewGuestName, NewGuestNotes))
            {
                ErrorMessage = "A guest with this name and note already exists. Use a distinct note if this is a different person.";
                return;
            }
        }
        catch
        {
            ErrorMessage = "Guest name could not be checked.";
            return;
        }

        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? "";
        var username = user.Identity?.Name ?? "unknown";

        try
        {
            await GuestEntryService.AddAsync(
                NewGuestName,
                NewGuestNotes,
                userId,
                username);
        }
        catch (InvalidOperationException exception)
        {
            ErrorMessage = exception.Message;
            return;
        }
        catch
        {
            ErrorMessage = "Guest could not be added.";
            return;
        }

        NewGuestName = "";
        NewGuestNotes = "";

        GuestEntries = await GuestEntryService.GetAllAsync();
    }
    
    protected async Task DeleteGuest(string? id)
    {
        if (string.IsNullOrWhiteSpace(id))
        {
            ErrorMessage = "Guest entry is missing an id.";
            return;
        }

        try
        {
            await GuestEntryService.DeleteAsync(id);
            GuestEntries = await GuestEntryService.GetAllAsync();
        }
        catch
        {
            ErrorMessage = "Guest could not be deleted.";
        }
    }
    
    protected void StartEdit(GuestEntryDocument guest)
    {
        EditingGuestId = guest.Id;
        EditGuestName = guest.Name;
        EditGuestNotes = guest.Notes ?? "";
        ErrorMessage = "";
    }

    protected void CancelEdit()
    {
        EditingGuestId = null;
        EditGuestName = "";
        EditGuestNotes = "";
    }
    
    protected async Task SaveEdit()
    {
        ErrorMessage = "";

        if (string.IsNullOrWhiteSpace(EditingGuestId))
        {
            ErrorMessage = "No guest entry is selected for editing.";
            return;
        }

        if (string.IsNullOrWhiteSpace(EditGuestName))
        {
            ErrorMessage = "Provide a guest name.";
            return;
        }

        try
        {
            if (await GuestEntryService.NameAndNotesExistAsync(EditGuestName, EditGuestNotes, EditingGuestId))
            {
                ErrorMessage = "A guest with this name and note already exists. Use a distinct note if this is a different person.";
                return;
            }
        }
        catch
        {
            ErrorMessage = "Guest name could not be checked.";
            return;
        }

        try
        {
            await GuestEntryService.UpdateAsync(
                EditingGuestId,
                EditGuestName,
                EditGuestNotes);
        }
        catch (InvalidOperationException exception)
        {
            ErrorMessage = exception.Message;
            return;
        }
        catch
        {
            ErrorMessage = "Guest could not be updated.";
            return;
        }

        EditingGuestId = null;
        EditGuestName = "";
        EditGuestNotes = "";

        GuestEntries = await GuestEntryService.GetAllAsync();
    }
}
