@page "/"
@layout EmptyLayout
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@using System.Text.Json
@using GestionaDenuncias.Shared.Models
@using GestionaDenunciasAN.Models
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject IJSRuntime JSRuntime
@inject NavigationManager Navigation
@inject UiBusyService Busy

<PageTitle>Portal de denuncias</PageTitle>

<style>
    .login-shell {
        min-height: 100vh;
        background:
            radial-gradient(circle at top left, rgba(90, 155, 213, 0.3), transparent 35%),
            linear-gradient(135deg, #f7fafc 0%, #dfe8f3 45%, #eef4fb 100%);
    }

    .login-panel {
        max-width: 440px;
        width: 100%;
        background: rgba(255, 255, 255, 0.92);
        border-radius: 24px;
        box-shadow: 0 25px 60px rgba(31, 73, 125, 0.18);
        border: 1px solid rgba(90, 155, 213, 0.15);
    }

    .brand-panel {
        color: #12395f;
        max-width: 560px;
    }

    .brand-kicker {
        display: inline-block;
        padding: 0.35rem 0.75rem;
        border-radius: 999px;
        background: rgba(42, 82, 152, 0.12);
        color: #1f497d;
        font-weight: 600;
        letter-spacing: 0.02em;
        text-transform: uppercase;
        font-size: 0.8rem;
    }

    .brand-title {
        font-size: clamp(2rem, 4vw, 3.5rem);
        line-height: 1.05;
        font-weight: 700;
        margin: 1rem 0;
    }

    .brand-copy {
        font-size: 1.05rem;
        color: #35597f;
        max-width: 34rem;
    }

    .login-label {
        font-size: 0.92rem;
        font-weight: 600;
        color: #244e79;
    }

    .login-input {
        border-radius: 14px;
        min-height: 3rem;
        border-color: #c7d6e7;
    }

    .login-input:focus {
        border-color: #2a5298;
        box-shadow: 0 0 0 0.2rem rgba(42, 82, 152, 0.12);
    }

    .login-button {
        min-height: 3rem;
        border-radius: 14px;
        background: linear-gradient(135deg, #2a5298, #1f497d);
        border: none;
        font-weight: 600;
    }
</style>

<div class="container-fluid login-shell d-flex align-items-center">
    <div class="container py-5">
        <div class="row g-5 align-items-center">
            <div class="col-lg-7">
                <div class="brand-panel">
                    <span class="brand-kicker">Oficina Antifraude de Andalucia</span>
                    <h1 class="brand-title">Una sola puerta para entrar, importar y tramitar denuncias.</h1>
                    <p class="brand-copy mb-4">
                        El acceso de la aplicacion ya se apoya en GlobalLeaks. La sesion interna de esta app se mantiene
                        activa de forma persistente, y cuando caduque la sesion de obtencion de denuncias solo habra que
                        renovar el codigo 2FA desde la bandeja de entrada.
                    </p>
                    <img src="Content/imagenes/logo-oaaf-negativo-transparente.svg"
                         alt="Logo Oficina Antifraude"
                         style="max-width: 320px; width: 100%;" />
                </div>
            </div>

            <div class="col-lg-5 d-flex justify-content-center">
                <div class="login-panel p-4 p-md-5">
                    <h2 class="h3 mb-2">Acceso con GlobalLeaks</h2>
                    <p class="text-muted mb-4">
                        Primero validamos usuario y contrasena. Despues te pediremos un codigo 2FA fresco para completar el acceso.
                    </p>

                    @if (!string.IsNullOrWhiteSpace(StatusMessage))
                    {
                        <div class="alert @StatusCss mb-4">@StatusMessage</div>
                    }

                    <div class="mb-3">
                        <label class="login-label mb-2">Usuario</label>
                        <input class="form-control login-input"
                               @bind="Username"
                               @bind:event="oninput"
                               disabled="@LoginPrepared"
                               autocomplete="username"
                               placeholder="usuario de GlobalLeaks" />
                    </div>

                    <div class="mb-3">
                        <label class="login-label mb-2">Contrasena</label>
                        <input class="form-control login-input"
                               type="password"
                               @bind="Password"
                               @bind:event="oninput"
                               disabled="@LoginPrepared"
                               autocomplete="current-password" />
                    </div>

                    @if (LoginPrepared)
                    {
                        <div class="alert alert-info mb-4">
                            Credenciales preparadas. Introduce ahora el codigo 2FA actual para completar el acceso.
                        </div>

                        <div class="mb-4">
                            <label class="login-label mb-2">Codigo 2FA</label>
                            <input class="form-control login-input"
                                   @bind="Authcode"
                                   @bind:event="oninput"
                                   @onkeydown="HandleAuthcodeKeyDown"
                                   inputmode="numeric"
                                   maxlength="6"
                                   placeholder="123456" />
                        </div>
                    }

                    <button class="btn btn-primary login-button w-100"
                            @onclick="LoginAsync"
                            disabled="@IsBusy">
                        @LoginButtonText
                    </button>
                    @if (LoginPrepared)
                    {
                        <button class="btn btn-link w-100 mt-3"
                                type="button"
                                disabled="@IsBusy"
                                @onclick="ResetPreparedLogin">
                            Cambiar usuario o contrasena
                        </button>
                    }
                </div>
            </div>
        </div>
    </div>
</div>

@code {
    [SupplyParameterFromQuery(Name = "returnUrl")]
    public string? ReturnUrl { get; set; }

    private string Username { get; set; } = string.Empty;
    private string Password { get; set; } = string.Empty;
    private string Authcode { get; set; } = string.Empty;
    private string PendingLoginId { get; set; } = string.Empty;
    private string StatusMessage { get; set; } = string.Empty;
    private string StatusCss { get; set; } = "alert-info";
    private bool IsBusy { get; set; }
    private bool LoginPrepared => !string.IsNullOrWhiteSpace(PendingLoginId);
    private string LoginButtonText => IsBusy
        ? (LoginPrepared ? "Validando 2FA..." : "Preparando acceso...")
        : (LoginPrepared ? "Validar 2FA y entrar" : "Preparar acceso");

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        if (authState.User.Identity?.IsAuthenticated == true)
        {
            Navigation.NavigateTo(GetTargetUrl(), true);
        }
    }

    private async Task LoginAsync()
    {
        StatusMessage = string.Empty;

        if (!LoginPrepared)
        {
            await PrepareLoginAsync();
            return;
        }

        await CompleteLoginAsync();
    }

    private async Task PrepareLoginAsync()
    {
        if (string.IsNullOrWhiteSpace(Username) ||
            string.IsNullOrWhiteSpace(Password))
        {
            SetStatus("Debes rellenar usuario y contrasena.", "alert-warning");
            return;
        }

        IsBusy = true;

        try
        {
            using var busy = Busy.Show(
                "Preparando acceso",
                "Validando usuario y contrasena con GlobalLeaks. Cuando termine pediremos un codigo 2FA nuevo.");

            using var loginTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(170));
            var response = await JSRuntime.InvokeAsync<ApiJsResponse>(
                "appAuthPostJson",
                loginTimeout.Token,
                [
                    "/api/auth/prepare",
                    new ApiLoginPrepareRequest(Username.Trim(), Password)
                ]);

            if (!response.Ok)
            {
                var error = ReadData<ApiError>(response);
                SetStatus(error?.Error ?? "No se ha podido preparar el acceso.", "alert-danger");
                return;
            }

            var prepared = ReadData<ApiLoginPrepareResponse>(response);
            if (prepared is null || string.IsNullOrWhiteSpace(prepared.PendingLoginId))
            {
                SetStatus("La API no ha devuelto una preparacion de login valida.", "alert-danger");
                return;
            }

            PendingLoginId = prepared.PendingLoginId;
            Username = prepared.Username;
            Password = string.Empty;
            Authcode = string.Empty;
            SetStatus("Credenciales preparadas. Introduce el codigo 2FA que este activo ahora mismo.", "alert-info");
        }
        catch (JSException ex)
        {
            SetStatus($"Fallo de comunicacion con el navegador: {ex.Message}", "alert-danger");
        }
        catch (OperationCanceledException)
        {
            SetStatus("La preparacion del acceso ha tardado demasiado. Revisa si ApiDenuncias o GlobalLeaks estan respondiendo lento y vuelve a intentarlo.", "alert-danger");
        }
        catch (Exception ex)
        {
            SetStatus($"No se ha podido preparar el acceso: {ex.Message}", "alert-danger");
        }
        finally
        {
            IsBusy = false;
        }
    }

    private async Task CompleteLoginAsync()
    {
        var authcode = Authcode.Trim();
        if (authcode.Length != 6 || authcode.Any(ch => !char.IsDigit(ch)))
        {
            SetStatus("El codigo 2FA debe tener exactamente 6 digitos.", "alert-warning");
            return;
        }

        IsBusy = true;

        try
        {
            using var busy = Busy.Show(
                "Validando 2FA",
                "Completando el acceso con el codigo actual de GlobalLeaks.");

            using var loginTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(170));
            var response = await JSRuntime.InvokeAsync<ApiJsResponse>(
                "appAuthPostJson",
                loginTimeout.Token,
                [
                    "/api/auth/complete",
                    new ApiLoginCompleteRequest(PendingLoginId, authcode)
                ]);

            if (!response.Ok)
            {
                var error = ReadData<ApiError>(response);
                SetStatus(error?.Error ?? "No se ha podido completar el inicio de sesion.", "alert-danger");
                Authcode = string.Empty;
                return;
            }

            Busy.Update(message: "Creando la sesion interna segura de la aplicacion.");
            Navigation.NavigateTo(GetTargetUrl(), true);
        }
        catch (JSException ex)
        {
            SetStatus($"Fallo de comunicacion con el navegador: {ex.Message}", "alert-danger");
        }
        catch (OperationCanceledException)
        {
            SetStatus("La validacion del 2FA ha tardado demasiado. Revisa si ApiDenuncias o GlobalLeaks estan respondiendo lento y vuelve a intentarlo.", "alert-danger");
        }
        catch (Exception ex)
        {
            SetStatus($"No se ha podido completar el inicio de sesion: {ex.Message}", "alert-danger");
        }
        finally
        {
            IsBusy = false;
        }
    }

    private Task HandleAuthcodeKeyDown(KeyboardEventArgs args)
        => LoginPrepared && args.Key == "Enter" ? LoginAsync() : Task.CompletedTask;

    private void ResetPreparedLogin()
    {
        PendingLoginId = string.Empty;
        Password = string.Empty;
        Authcode = string.Empty;
        StatusMessage = string.Empty;
    }

    private void SetStatus(string message, string cssClass)
    {
        StatusMessage = message;
        StatusCss = cssClass;
    }

    private string GetTargetUrl()
    {
        if (!string.IsNullOrWhiteSpace(ReturnUrl) &&
            ReturnUrl.StartsWith("/", StringComparison.Ordinal) &&
            !ReturnUrl.StartsWith("//", StringComparison.Ordinal))
        {
            return ReturnUrl;
        }

        return "/GestionZip";
    }

    private static T? ReadData<T>(ApiJsResponse response)
    {
        if (response.Data.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
        {
            return default;
        }

        return response.Data.Deserialize<T>(new JsonSerializerOptions(JsonSerializerDefaults.Web));
    }

    private sealed class ApiJsResponse
    {
        public bool Ok { get; set; }
        public int Status { get; set; }
        public JsonElement Data { get; set; }
    }
}
