@using System
@using System.Collections.Generic
@using System.Linq
@inject NavigationManager NavigationManager
@inject LookupService LookupService
@inject RolemasterDb.App.Frontend.AppState.TableContextState TableContextState

<section class="panel diagnostics-page tooling-surface">
    <header class="diagnostics-page-header">
        <div>
            <h2 class="panel-title">Critical Cell Diagnostics</h2>
            <p class="panel-copy">Engineering-only parser metadata, provenance, and payload inspection live here instead of inside the normal curation modal.</p>
        </div>
    </header>

    @if (referenceData is null)
    {
        <p class="muted">Loading table list...</p>
    }
    else if (!referenceData.CriticalTables.Any())
    {
        <p class="muted">No critical tables are available yet.</p>
    }
    else if (!hasInitializedContext)
    {
        <p class="muted">Restoring diagnostic context...</p>
    }
    else
    {
        <div class="diagnostics-selector-grid">
            <div class="field-shell">
                <label for="diagnostics-table-select">Table</label>
                <select
                    id="diagnostics-table-select"
                    class="input-shell"
                    value="@selectedTableSlug"
                    @onchange="HandleTableChanged"
                    disabled="@isBusy">
                    @foreach (var table in referenceData.CriticalTables)
                    {
                        <option value="@table.Key">@table.Label</option>
                    }
                </select>
            </div>

            <div class="field-shell">
                <label for="diagnostics-roll-band-select">Roll Band</label>
                <select
                    id="diagnostics-roll-band-select"
                    class="input-shell"
                    value="@selectedRollBand"
                    @onchange="HandleRollBandChanged"
                    disabled="@(isBusy || tableDetail is null || !tableDetail.RollBands.Any())">
                    @if (tableDetail is not null)
                    {
                        @foreach (var rollBand in tableDetail.RollBands)
                        {
                            <option value="@rollBand.Label">@rollBand.Label</option>
                        }
                    }
                </select>
            </div>

            @if (tableDetail is { Groups.Count: > 0 })
            {
                <div class="field-shell">
                    <label for="diagnostics-group-select">Variant</label>
                    <select
                        id="diagnostics-group-select"
                        class="input-shell"
                        value="@selectedGroupKey"
                        @onchange="HandleGroupChanged"
                        disabled="@isBusy">
                        @foreach (var group in tableDetail.Groups)
                        {
                            <option value="@group.Key">@group.Label</option>
                        }
                    </select>
                </div>
            }

            <div class="field-shell">
                <label for="diagnostics-column-select">Severity</label>
                <select
                    id="diagnostics-column-select"
                    class="input-shell"
                    value="@selectedColumnKey"
                    @onchange="HandleColumnChanged"
                    disabled="@(isBusy || tableDetail is null || !tableDetail.Columns.Any())">
                    @if (tableDetail is not null)
                    {
                        @foreach (var column in tableDetail.Columns)
                        {
                            <option value="@column.Key">@column.Label</option>
                        }
                    }
                </select>
            </div>
        </div>

        @if (!string.IsNullOrWhiteSpace(detailError))
        {
            <p class="error-text">@detailError</p>
        }
        else if (tableDetail is null)
        {
            <p class="muted">The selected table could not be loaded.</p>
        }
        else if (!tableDetail.Cells.Any())
        {
            <p class="muted">The selected table has no filled cells to inspect.</p>
        }
        else if (selectedCell is null)
        {
            <div class="critical-editor-card nested">
                <div class="critical-editor-card-header">
                    <div>
                        <strong>No Filled Cell At This Position</strong>
                        <p class="muted critical-editor-inline-copy">Pick another roll band, variant, or severity to inspect a stored result.</p>
                    </div>
                </div>
            </div>
        }
        else
        {
            <div class="diagnostics-selection-summary">
                <strong>Inspecting</strong>
                <span>@tableDetail.DisplayName</span>
                <span>· Roll band <strong>@selectedCell.RollBand</strong></span>
                <span>· Severity <strong>@selectedCell.ColumnLabel</strong></span>
                @if (!string.IsNullOrWhiteSpace(selectedCell.GroupLabel))
                {
                    <span>· Variant <strong>@selectedCell.GroupLabel</strong></span>
                }
                <span>· Result ID <strong>@selectedCell.ResultId</strong></span>
            </div>

            @if (isDiagnosticsLoading)
            {
                <p class="muted">Loading diagnostics...</p>
            }
            else if (!string.IsNullOrWhiteSpace(diagnosticsError))
            {
                <p class="error-text">@diagnosticsError</p>
            }
            else if (diagnosticsModel is not null)
            {
                <CriticalCellEngineeringDiagnostics Model="diagnosticsModel" />
            }
        }
    }
</section>

@code {
    private LookupReferenceData? referenceData;
    private CriticalTableDetail? tableDetail;
    private CriticalTableCellDetail? selectedCell;
    private CriticalCellEditorModel? diagnosticsModel;
    private string selectedTableSlug = string.Empty;
    private string selectedRollBand = string.Empty;
    private string selectedColumnKey = string.Empty;
    private string? selectedGroupKey;
    private bool isDetailLoading;
    private bool isDiagnosticsLoading;
    private string? detailError;
    private string? diagnosticsError;
    private bool hasInitializedContext;

    private bool isBusy => isDetailLoading || isDiagnosticsLoading;
    private string ContextDestination => "tools.diagnostics";

    protected override async Task OnInitializedAsync()
    {
        referenceData = await LookupService.GetReferenceDataAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!firstRender || hasInitializedContext || referenceData?.CriticalTables.Count is not > 0)
        {
            return;
        }

        var initialContext = await TableContextState.RestoreAsync(
            NavigationManager.Uri,
            ContextDestination,
            referenceData.CriticalTables,
            RolemasterDb.App.Frontend.AppState.TableContextMode.Diagnostics);

        selectedTableSlug = initialContext.TableSlug ?? string.Empty;
        hasInitializedContext = true;
        await LoadTableDetailAsync(initialContext);
        await InvokeAsync(StateHasChanged);
    }

    private async Task HandleTableChanged(ChangeEventArgs args)
    {
        selectedTableSlug = args.Value?.ToString() ?? string.Empty;
        await LoadTableDetailAsync();
    }

    private async Task HandleRollBandChanged(ChangeEventArgs args)
    {
        selectedRollBand = args.Value?.ToString() ?? string.Empty;
        ResolveSelectedCell();
        await PersistAndSyncRouteContextAsync();
        await LoadSelectedCellDiagnosticsAsync();
    }

    private async Task HandleGroupChanged(ChangeEventArgs args)
    {
        selectedGroupKey = NormalizeOptionalText(args.Value?.ToString());
        ResolveSelectedCell();
        await PersistAndSyncRouteContextAsync();
        await LoadSelectedCellDiagnosticsAsync();
    }

    private async Task HandleColumnChanged(ChangeEventArgs args)
    {
        selectedColumnKey = args.Value?.ToString() ?? string.Empty;
        ResolveSelectedCell();
        await PersistAndSyncRouteContextAsync();
        await LoadSelectedCellDiagnosticsAsync();
    }

    private async Task LoadTableDetailAsync(RolemasterDb.App.Frontend.AppState.TableContextSnapshot? routeContext = null)
    {
        if (string.IsNullOrWhiteSpace(selectedTableSlug))
        {
            tableDetail = null;
            selectedCell = null;
            diagnosticsModel = null;
            return;
        }

        isDetailLoading = true;
        detailError = null;
        diagnosticsError = null;
        diagnosticsModel = null;
        selectedCell = null;

        try
        {
            tableDetail = await LookupService.GetCriticalTableAsync(selectedTableSlug);
            if (tableDetail is null)
            {
                detailError = "The selected table could not be loaded.";
                return;
            }

            if (!TryApplySelectionFromContext(tableDetail, routeContext))
            {
                SetDefaultSelection(tableDetail);
            }

            ResolveSelectedCell();
            if (selectedCell is null && routeContext is not null)
            {
                SetDefaultSelection(tableDetail);
                ResolveSelectedCell();
            }

            await PersistAndSyncRouteContextAsync();
            await LoadSelectedCellDiagnosticsAsync();
        }
        catch (Exception exception)
        {
            detailError = exception.Message;
            tableDetail = null;
            selectedCell = null;
            diagnosticsModel = null;
        }
        finally
        {
            isDetailLoading = false;
        }
    }

    private void SetDefaultSelection(CriticalTableDetail detail)
    {
        if (!detail.Cells.Any())
        {
            selectedRollBand = detail.RollBands.FirstOrDefault()?.Label ?? string.Empty;
            selectedColumnKey = detail.Columns.FirstOrDefault()?.Key ?? string.Empty;
            selectedGroupKey = detail.Groups.FirstOrDefault()?.Key;
            return;
        }

        var rollOrder = detail.RollBands
            .Select((rollBand, index) => new { rollBand.Label, index })
            .ToDictionary(item => item.Label, item => item.index, StringComparer.Ordinal);
        var columnOrder = detail.Columns
            .Select((column, index) => new { column.Key, index })
            .ToDictionary(item => item.Key, item => item.index, StringComparer.Ordinal);
        var groupOrder = detail.Groups
            .Select((group, index) => new { group.Key, index })
            .ToDictionary(item => item.Key, item => item.index, StringComparer.Ordinal);

        var firstCell = detail.Cells
            .OrderBy(cell => rollOrder.GetValueOrDefault(cell.RollBand, int.MaxValue))
            .ThenBy(cell =>
            {
                if (cell.GroupKey is null)
                {
                    return -1;
                }

                return groupOrder.GetValueOrDefault(cell.GroupKey, int.MaxValue);
            })
            .ThenBy(cell => columnOrder.GetValueOrDefault(cell.ColumnKey, int.MaxValue))
            .First();

        selectedRollBand = firstCell.RollBand;
        selectedColumnKey = firstCell.ColumnKey;
        selectedGroupKey = firstCell.GroupKey;
    }

    private void ResolveSelectedCell()
    {
        if (tableDetail is null)
        {
            selectedCell = null;
            return;
        }

        selectedCell = tableDetail.Cells.FirstOrDefault(cell =>
            string.Equals(cell.RollBand, selectedRollBand, StringComparison.Ordinal) &&
            string.Equals(cell.ColumnKey, selectedColumnKey, StringComparison.Ordinal) &&
            string.Equals(cell.GroupKey ?? string.Empty, selectedGroupKey ?? string.Empty, StringComparison.Ordinal));
    }

    private bool TryApplySelectionFromContext(
        CriticalTableDetail detail,
        RolemasterDb.App.Frontend.AppState.TableContextSnapshot? routeContext)
    {
        if (routeContext is null)
        {
            return false;
        }

        CriticalTableCellDetail? matchedCell = null;
        if (routeContext.ResultId is { } resultId)
        {
            matchedCell = detail.Cells.FirstOrDefault(cell => cell.ResultId == resultId);
        }

        matchedCell ??= detail.Cells.FirstOrDefault(cell =>
            string.Equals(cell.RollBand, routeContext.RollBand, StringComparison.Ordinal) &&
            string.Equals(cell.ColumnKey, routeContext.ColumnKey, StringComparison.Ordinal) &&
            string.Equals(cell.GroupKey ?? string.Empty, routeContext.GroupKey ?? string.Empty, StringComparison.Ordinal));

        if (matchedCell is not null)
        {
            selectedRollBand = matchedCell.RollBand;
            selectedColumnKey = matchedCell.ColumnKey;
            selectedGroupKey = matchedCell.GroupKey;
            return true;
        }

        if (string.IsNullOrWhiteSpace(routeContext.RollBand) &&
            string.IsNullOrWhiteSpace(routeContext.ColumnKey) &&
            string.IsNullOrWhiteSpace(routeContext.GroupKey))
        {
            return false;
        }

        selectedRollBand = ResolveRollBand(detail, routeContext.RollBand);
        selectedColumnKey = ResolveColumnKey(detail, routeContext.ColumnKey);
        selectedGroupKey = ResolveGroupKey(detail, routeContext.GroupKey);
        return true;
    }

    private async Task LoadSelectedCellDiagnosticsAsync()
    {
        diagnosticsError = null;
        diagnosticsModel = null;

        if (selectedCell is null || string.IsNullOrWhiteSpace(selectedTableSlug))
        {
            return;
        }

        isDiagnosticsLoading = true;

        try
        {
            var response = await LookupService.GetCriticalCellEditorAsync(selectedTableSlug, selectedCell.ResultId);
            if (response is null)
            {
                diagnosticsError = "The selected cell could not be loaded.";
                return;
            }

            diagnosticsModel = CriticalCellEditorModel.FromResponse(response);
            await PersistAndSyncRouteContextAsync();
        }
        catch (Exception exception)
        {
            diagnosticsError = exception.Message;
        }
        finally
        {
            isDiagnosticsLoading = false;
        }
    }

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

    private async Task PersistAndSyncRouteContextAsync()
    {
        if (string.IsNullOrWhiteSpace(selectedTableSlug))
        {
            return;
        }

        var snapshot = new RolemasterDb.App.Frontend.AppState.TableContextSnapshot(
            TableSlug: selectedTableSlug,
            GroupKey: selectedGroupKey,
            ColumnKey: selectedColumnKey,
            RollBand: selectedRollBand,
            ResultId: selectedCell?.ResultId,
            Mode: RolemasterDb.App.Frontend.AppState.TableContextMode.Diagnostics);

        await TableContextState.PersistAsync(ContextDestination, snapshot);

        var targetUri = TableContextState.BuildUri("/tools/diagnostics", snapshot);
        if (string.Equals(NavigationManager.ToBaseRelativePath(NavigationManager.Uri), targetUri.TrimStart('/'), StringComparison.Ordinal))
        {
            return;
        }

        NavigationManager.NavigateTo(targetUri, replace: true);
    }

    private static string ResolveRollBand(CriticalTableDetail detail, string? rollBand) =>
        detail.RollBands.FirstOrDefault(item => string.Equals(item.Label, rollBand, StringComparison.Ordinal))?.Label
        ?? detail.RollBands.FirstOrDefault()?.Label
        ?? string.Empty;

    private static string ResolveColumnKey(CriticalTableDetail detail, string? columnKey) =>
        detail.Columns.FirstOrDefault(item => string.Equals(item.Key, columnKey, StringComparison.Ordinal))?.Key
        ?? detail.Columns.FirstOrDefault()?.Key
        ?? string.Empty;

    private static string? ResolveGroupKey(CriticalTableDetail detail, string? groupKey)
    {
        if (detail.Groups.Count == 0)
        {
            return null;
        }

        return detail.Groups.FirstOrDefault(item => string.Equals(item.Key, groupKey, StringComparison.Ordinal))?.Key
            ?? detail.Groups.First().Key;
    }
}
