@using System.ComponentModel.DataAnnotations
@using System.Net.Http.Json
@using System.Security.Claims
@using ChessCubing.App.Models.Auth
@using Microsoft.AspNetCore.Components.Authorization
@implements IDisposable
@inject AppAuthenticationStateProvider AuthenticationStateProvider
@inject HttpClient Http
@inject NavigationManager Navigation

<div class="site-menu-shell">
    <header class="site-menu-bar">
        <div class="site-menu-main">
            <a class="site-menu-brand" href="index.html" aria-label="Accueil ChessCubing">
                <img class="site-menu-brand-icon" src="logo.png" alt="Icone ChessCubing" />
                <span class="site-menu-brand-copy">
                    <span class="micro-label">ChessCubing Arena</span>
                    <strong>Menu general</strong>
                </span>
            </a>

            <nav class="site-menu-links" aria-label="Navigation principale">
                <a class="@BuildNavLinkClass(HomePaths)" href="index.html" aria-current="@BuildAriaCurrent(HomePaths)">Accueil</a>
                <a class="@BuildNavLinkClass(ApplicationPaths)" href="application.html" aria-current="@BuildAriaCurrent(ApplicationPaths)">Application</a>
                <a class="@BuildNavLinkClass(RulesPaths)" href="reglement.html" aria-current="@BuildAriaCurrent(RulesPaths)">Reglement</a>
            </nav>

            <div class="site-menu-account">
                <span class="micro-label">Compte joueur</span>
                @if (IsAuthenticated)
                {
                    <div class="site-menu-account-panel">
                        <div class="site-menu-user">
                            <strong>@DisplayName</strong>
                            <span>@DisplayMeta</span>
                        </div>
                        <button class="button ghost small" type="button" @onclick="LogoutAsync" disabled="@IsSubmitting">Se deconnecter</button>
                    </div>
                }
                else
                {
                    <div class="site-menu-account-actions">
                        <button class="button secondary small" type="button" @onclick="OpenLoginModal">Se connecter</button>
                        <button class="button ghost small" type="button" @onclick="OpenRegisterModal">Creer un compte</button>
                    </div>
                }
            </div>
        </div>
    </header>
</div>

<section class="modal @(ShowAuthModal ? string.Empty : "hidden")" aria-hidden="@BoolString(!ShowAuthModal)">
    <div class="modal-backdrop" @onclick="CloseAuthModal"></div>
    <div class="modal-card auth-modal-card">
        <div class="modal-head">
            <div>
                <p class="eyebrow">Compte joueur</p>
                <h2>@AuthModalTitle</h2>
            </div>
            <button class="button ghost small" type="button" @onclick="CloseAuthModal" disabled="@IsSubmitting">Fermer</button>
        </div>

        <p class="auth-modal-copy">
            L'authentification se fait maintenant directement dans l'application, sans redirection vers une page externe.
        </p>

        <div class="auth-modal-switch">
            <button class="@BuildModeButtonClass(AuthMode.Login)" type="button" @onclick="SwitchToLogin" disabled="@IsSubmitting">Se connecter</button>
            <button class="@BuildModeButtonClass(AuthMode.Register)" type="button" @onclick="SwitchToRegister" disabled="@IsSubmitting">Creer un compte</button>
        </div>

        @if (!string.IsNullOrWhiteSpace(FormError))
        {
            <p class="auth-form-error">@FormError</p>
        }

        @if (Mode == AuthMode.Login)
        {
            <EditForm Model="@LoginModel" OnValidSubmit="SubmitLoginAsync">
                <DataAnnotationsValidator />
                <div class="auth-form-grid">
                    <label class="field">
                        <span>Identifiant ou email</span>
                        <InputText @bind-Value="LoginModel.Username" autocomplete="username email" />
                        <ValidationMessage For="@(() => LoginModel.Username)" />
                    </label>

                    <label class="field">
                        <span>Mot de passe</span>
                        <InputText @bind-Value="LoginModel.Password" type="password" autocomplete="current-password" />
                        <ValidationMessage For="@(() => LoginModel.Password)" />
                    </label>
                </div>

                <div class="modal-actions">
                    <button class="button secondary" type="submit" disabled="@IsSubmitting">
                        @(IsSubmitting ? "Connexion..." : "Se connecter")
                    </button>
                </div>
            </EditForm>
        }
        else
        {
            <EditForm Model="@RegisterModel" OnValidSubmit="SubmitRegisterAsync">
                <DataAnnotationsValidator />
                <div class="auth-form-grid two-columns">
                    <label class="field">
                        <span>Prenom</span>
                        <InputText @bind-Value="RegisterModel.FirstName" autocomplete="given-name" />
                    </label>

                    <label class="field">
                        <span>Nom</span>
                        <InputText @bind-Value="RegisterModel.LastName" autocomplete="family-name" />
                    </label>

                    <label class="field">
                        <span>Nom d'utilisateur</span>
                        <InputText @bind-Value="RegisterModel.Username" autocomplete="username" />
                        <ValidationMessage For="@(() => RegisterModel.Username)" />
                    </label>

                    <label class="field">
                        <span>Email</span>
                        <InputText @bind-Value="RegisterModel.Email" autocomplete="email" />
                        <ValidationMessage For="@(() => RegisterModel.Email)" />
                    </label>

                    <label class="field">
                        <span>Mot de passe</span>
                        <InputText @bind-Value="RegisterModel.Password" type="password" autocomplete="new-password" />
                        <ValidationMessage For="@(() => RegisterModel.Password)" />
                    </label>

                    <label class="field">
                        <span>Confirmation du mot de passe</span>
                        <InputText @bind-Value="RegisterModel.ConfirmPassword" type="password" autocomplete="new-password" />
                        <ValidationMessage For="@(() => RegisterModel.ConfirmPassword)" />
                    </label>
                </div>

                <div class="modal-actions">
                    <button class="button secondary" type="submit" disabled="@IsSubmitting">
                        @(IsSubmitting ? "Creation..." : "Creer mon compte")
                    </button>
                </div>
            </EditForm>
        }
    </div>
</section>

@code {
    private static readonly string[] HomePaths = ["", "index.html"];
    private static readonly string[] ApplicationPaths = ["application", "application.html"];
    private static readonly string[] RulesPaths = ["reglement", "reglement.html"];

    private readonly LoginFormModel LoginModel = new();
    private readonly RegisterFormModel RegisterModel = new();

    private bool IsAuthenticated;
    private bool ShowAuthModal;
    private bool IsSubmitting;
    private string? FormError;
    private string AuthModalTitle = "Se connecter";
    private AuthMode Mode = AuthMode.Login;
    private string DisplayName = "Utilisateur connecte";
    private string DisplayMeta = "Session active";

    private string CurrentPath
    {
        get
        {
            var absolutePath = new Uri(Navigation.Uri).AbsolutePath;
            return absolutePath.Trim('/');
        }
    }

    protected override async Task OnInitializedAsync()
    {
        AuthenticationStateProvider.AuthenticationStateChanged += HandleAuthenticationStateChanged;
        await RefreshAuthenticationStateAsync();
    }

    private string BuildNavLinkClass(string[] paths)
        => IsCurrentPage(paths) ? "site-menu-link is-active" : "site-menu-link";

    private string? BuildAriaCurrent(string[] paths)
        => IsCurrentPage(paths) ? "page" : null;

    private bool IsCurrentPage(string[] paths)
        => paths.Any(path => string.Equals(CurrentPath, path, StringComparison.OrdinalIgnoreCase));

    private void OpenLoginModal()
    {
        ShowAuthModal = true;
        SwitchToLogin();
    }

    private void OpenRegisterModal()
    {
        ShowAuthModal = true;
        SwitchToRegister();
    }

    private void CloseAuthModal()
    {
        if (IsSubmitting)
        {
            return;
        }

        ShowAuthModal = false;
        FormError = null;
    }

    private void SwitchToLogin()
    {
        Mode = AuthMode.Login;
        AuthModalTitle = "Se connecter";
        FormError = null;
    }

    private void SwitchToRegister()
    {
        Mode = AuthMode.Register;
        AuthModalTitle = "Creer un compte";
        FormError = null;
    }

    private string BuildModeButtonClass(AuthMode mode)
        => mode == Mode ? "button secondary small" : "button ghost small";

    private async Task SubmitLoginAsync()
    {
        await SubmitAsync(
            "api/auth/login",
            new LoginRequest
            {
                Username = LoginModel.Username.Trim(),
                Password = LoginModel.Password,
            },
            "Connexion impossible.");
    }

    private async Task SubmitRegisterAsync()
    {
        await SubmitAsync(
            "api/auth/register",
            new RegisterRequest
            {
                Username = RegisterModel.Username.Trim(),
                Email = RegisterModel.Email.Trim(),
                Password = RegisterModel.Password,
                ConfirmPassword = RegisterModel.ConfirmPassword,
                FirstName = RegisterModel.FirstName?.Trim(),
                LastName = RegisterModel.LastName?.Trim(),
            },
            "Creation du compte impossible.");
    }

    private async Task SubmitAsync<TRequest>(string endpoint, TRequest payload, string fallbackMessage)
    {
        if (IsSubmitting)
        {
            return;
        }

        IsSubmitting = true;
        FormError = null;

        try
        {
            var response = await Http.PostAsJsonAsync(endpoint, payload);
            if (!response.IsSuccessStatusCode)
            {
                FormError = await ReadErrorAsync(response, fallbackMessage);
                return;
            }

            var session = await response.Content.ReadFromJsonAsync<AuthSessionResponse>();
            if (session is not null && session.IsAuthenticated)
            {
                AuthenticationStateProvider.SetAuthenticated(session);
            }
            else
            {
                await AuthenticationStateProvider.RefreshAsync();
            }

            ShowAuthModal = false;
            FormError = null;
            ResetForms();
            await RefreshAuthenticationStateAsync();
        }
        catch
        {
            FormError = fallbackMessage;
        }
        finally
        {
            IsSubmitting = false;
        }
    }

    private async Task LogoutAsync()
    {
        if (IsSubmitting)
        {
            return;
        }

        IsSubmitting = true;
        FormError = null;

        try
        {
            await Http.PostAsync("api/auth/logout", null);
            AuthenticationStateProvider.SetAnonymous();
            await RefreshAuthenticationStateAsync();
        }
        finally
        {
            IsSubmitting = false;
        }
    }

    private void HandleAuthenticationStateChanged(Task<AuthenticationState> authenticationStateTask)
        => _ = InvokeAsync(RefreshAuthenticationStateAsync);

    private async Task RefreshAuthenticationStateAsync()
    {
        try
        {
            var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
            var user = authState.User;

            if (user.Identity?.IsAuthenticated == true)
            {
                IsAuthenticated = true;
                DisplayName = BuildDisplayName(user);
                DisplayMeta = BuildMeta(user);
            }
            else
            {
                ResetAuthenticationDisplay();
            }
        }
        catch
        {
            ResetAuthenticationDisplay();
        }

        StateHasChanged();
    }

    private void ResetAuthenticationDisplay()
    {
        IsAuthenticated = false;
        DisplayName = "Utilisateur connecte";
        DisplayMeta = "Session active";
    }

    private void ResetForms()
    {
        LoginModel.Username = string.Empty;
        LoginModel.Password = string.Empty;
        RegisterModel.FirstName = string.Empty;
        RegisterModel.LastName = string.Empty;
        RegisterModel.Username = string.Empty;
        RegisterModel.Email = string.Empty;
        RegisterModel.Password = string.Empty;
        RegisterModel.ConfirmPassword = string.Empty;
    }

    private static string BuildDisplayName(ClaimsPrincipal user)
        => user.FindFirst("name")?.Value
            ?? user.FindFirst("preferred_username")?.Value
            ?? user.Identity?.Name
            ?? "Utilisateur connecte";

    private static string BuildMeta(ClaimsPrincipal user)
        => user.FindFirst("email")?.Value
            ?? "Session active";

    private static async Task<string> ReadErrorAsync(HttpResponseMessage response, string fallbackMessage)
    {
        try
        {
            var error = await response.Content.ReadFromJsonAsync<ApiErrorMessage>();
            if (!string.IsNullOrWhiteSpace(error?.Message))
            {
                return error.Message;
            }
        }
        catch
        {
        }

        return fallbackMessage;
    }

    private static string BoolString(bool value)
        => value ? "true" : "false";

    public void Dispose()
        => AuthenticationStateProvider.AuthenticationStateChanged -= HandleAuthenticationStateChanged;

    private enum AuthMode
    {
        Login,
        Register,
    }

    private sealed class ApiErrorMessage
    {
        public string? Message { get; set; }
    }

    private sealed class LoginFormModel
    {
        [Required(ErrorMessage = "L'identifiant est obligatoire.")]
        public string Username { get; set; } = string.Empty;

        [Required(ErrorMessage = "Le mot de passe est obligatoire.")]
        public string Password { get; set; } = string.Empty;
    }

    private sealed class RegisterFormModel
    {
        public string? FirstName { get; set; }

        public string? LastName { get; set; }

        [Required(ErrorMessage = "Le nom d'utilisateur est obligatoire.")]
        public string Username { get; set; } = string.Empty;

        [Required(ErrorMessage = "L'email est obligatoire.")]
        [EmailAddress(ErrorMessage = "L'email n'est pas valide.")]
        public string Email { get; set; } = string.Empty;

        [Required(ErrorMessage = "Le mot de passe est obligatoire.")]
        [MinLength(8, ErrorMessage = "Le mot de passe doit contenir au moins 8 caracteres.")]
        public string Password { get; set; } = string.Empty;

        [Required(ErrorMessage = "La confirmation est obligatoire.")]
        [Compare(nameof(Password), ErrorMessage = "Les mots de passe ne correspondent pas.")]
        public string ConfirmPassword { get; set; } = string.Empty;
    }
}
