@using System
@using System.Collections.Generic
@using System.Linq
@using System.Text.Json
@using RolemasterDb.App.Domain
@using RolemasterDb.App.Features

<div class="critical-editor-backdrop" @onclick="HandleBackdropClicked">
    <div class="critical-editor-dialog" @onclick:stopPropagation="true">
        <header class="critical-editor-header">
            <div>
                @if (Model is not null)
                {
                    <h3 class="panel-title">Edit Result Card</h3>
                    <p class="muted critical-editor-meta">
                        <strong>@Model.TableName</strong>
                        <span> · Roll band <strong>@Model.RollBand</strong></span>
                        <span> · Severity <strong>@Model.ColumnLabel</strong></span>
                        @if (!string.IsNullOrWhiteSpace(Model.GroupLabel))
                        {
                            <span> · Variant <strong>@Model.GroupLabel</strong></span>
                        }
                    </p>
                }
                else
                {
                    <h3 class="panel-title">Edit Result Card</h3>
                }
            </div>
            <button type="button" class="btn btn-link critical-editor-close" @onclick="OnClose">Close</button>
        </header>

        @if (IsLoading)
        {
            <div class="critical-editor-body">
                <p class="muted">Loading editor...</p>
            </div>
        }
        else if (!string.IsNullOrWhiteSpace(LoadErrorMessage))
        {
            <div class="critical-editor-body">
                <p class="error-text critical-editor-error">@LoadErrorMessage</p>
            </div>
        }
        else if (Model is not null)
        {
            <EditForm Model="Model" OnSubmit="HandleSubmitAsync" class="critical-editor-form">
                <div class="critical-editor-body">
                    @if (!string.IsNullOrWhiteSpace(ReparseErrorMessage))
                    {
                        <p class="error-text critical-editor-error">@ReparseErrorMessage</p>
                    }

                    @if (!string.IsNullOrWhiteSpace(SaveErrorMessage))
                    {
                        <p class="error-text critical-editor-error">@SaveErrorMessage</p>
                    }

                    <section class="critical-editor-section">
                        <div class="critical-editor-section-header">
                            <div>
                                <h4>Result Preview</h4>
                                <p class="muted">This is the card the table browser will show.</p>
                            </div>
                        </div>
                        <div class="result-card critical-editor-preview-card">
                            <div class="result-stats">
                                <span class="stat-pill">Severity: @Model.ColumnLabel</span>
                                <span class="stat-pill">Roll band: @Model.RollBand</span>
                                @if (!string.IsNullOrWhiteSpace(Model.GroupLabel))
                                {
                                    <span class="stat-pill">Variant: @Model.GroupLabel</span>
                                }
                            </div>
                            <CompactCriticalCell
                                Description="@Model.DescriptionText"
                                Effects="@BuildPreviewEffects(Model.Effects)"
                                Branches="@BuildPreviewBranches(Model.Branches)" />
                        </div>
                    </section>

                    <section class="critical-editor-section">
                        <div class="critical-editor-section-header">
                            <div>
                                <h4>Raw Text</h4>
                                <p class="muted">Update the source text, then adjust the visible card fields below.</p>
                            </div>
                            <button type="button" class="btn-ritual" @onclick="OnReparse" disabled="@IsSaving || IsReparsing">
                                @(IsReparsing ? "Re-Parsing..." : "Re-Parse Raw Text")
                            </button>
                        </div>
                        <div class="field-shell">
                            <label>Raw Cell Text</label>
                            <InputTextArea class="input-shell critical-editor-textarea tall" @bind-Value="Model.RawCellText" />
                        </div>
                        @if (Model.ValidationMessages.Count > 0)
                        {
                            <p class="muted critical-editor-advanced-hint">@GetParserNoteSummary(Model.ValidationMessages.Count)</p>
                        }
                        <div class="field-shell">
                            <label>Result Text Override</label>
                            <InputTextArea class="input-shell critical-editor-textarea compact" @bind-Value="Model.DescriptionText" />
                        </div>
                    </section>

                    <section class="critical-editor-section">
                        <div class="critical-editor-section-header">
                            <div>
                                <h4>Base Effects</h4>
                                <p class="muted">These chips appear on the main result.</p>
                            </div>
                            <button type="button" class="btn-ritual" @onclick="AddBaseEffect">Add Effect</button>
                        </div>
                        @if (Model.Effects.Count == 0)
                        {
                            <p class="muted">No base effects on this result yet.</p>
                        }
                        else
                        {
                            <div class="critical-editor-chip-list">
                                @for (var index = 0; index < Model.Effects.Count; index++)
                                {
                                    var effect = Model.Effects[index];
                                    var effectIndex = index;
                                    <div class="critical-editor-chip-card">
                                        <div class="critical-editor-chip-preview">
                                            <AffixBadgeList Effects="@BuildSinglePreviewEffect(effect)" />
                                            <span class="critical-editor-chip-name">@GetEffectLabel(effect)</span>
                                        </div>
                                        <button type="button" class="btn btn-link" @onclick="() => RemoveBaseEffect(effectIndex)">Remove</button>
                                    </div>
                                }
                            </div>

                            @for (var index = 0; index < Model.Effects.Count; index++)
                            {
                                var effect = Model.Effects[index];
                                <div class="critical-editor-card nested">
                                    <div class="critical-editor-card-header">
                                        <strong>@GetEffectLabel(effect)</strong>
                                    </div>
                                    @EffectFields(effect)
                                </div>
                            }
                        }
                    </section>

                    <section class="critical-editor-section">
                        <div class="critical-editor-section-header">
                            <div>
                                <h4>Conditions</h4>
                                <p class="muted">Use condition cards for alternate outcomes.</p>
                            </div>
                            <button type="button" class="btn-ritual" @onclick="AddBranch">Add Condition</button>
                        </div>
                        @if (Model.Branches.Count == 0)
                        {
                            <p class="muted">No alternate condition cards on this result yet.</p>
                        }
                        else
                        {
                            @for (var index = 0; index < Model.Branches.Count; index++)
                            {
                                var branch = Model.Branches[index];
                                <div class="critical-editor-card branch-card-editor">
                                    <div class="critical-editor-card-header">
                                        <div>
                                            <strong>@GetBranchTitle(branch, index)</strong>
                                            <p class="muted critical-editor-inline-copy">Shown when this condition applies.</p>
                                        </div>
                                        <button type="button" class="btn btn-link" @onclick="() => RemoveBranch(index)">Remove</button>
                                    </div>
                                    <div class="field-shell">
                                        <label>Condition</label>
                                        <InputText class="input-shell" @bind-Value="branch.ConditionText" />
                                    </div>
                                    <div class="field-shell">
                                        <label>Outcome Text</label>
                                        <InputTextArea class="input-shell critical-editor-textarea compact" @bind-Value="branch.DescriptionText" />
                                    </div>

                                    <div class="critical-editor-subsection">
                                        <div class="critical-editor-section-header">
                                            <div>
                                                <h5>Condition Effects</h5>
                                                <p class="muted">These chips only appear when the condition is met.</p>
                                            </div>
                                            <button type="button" class="btn-ritual" @onclick="() => AddBranchEffect(branch)">Add Effect</button>
                                        </div>
                                        @if (branch.Effects.Count == 0)
                                        {
                                            <p class="muted">No effects on this condition card yet.</p>
                                        }
                                        else
                                        {
                                            <div class="critical-editor-chip-list">
                                                @for (var effectIndex = 0; effectIndex < branch.Effects.Count; effectIndex++)
                                                {
                                                    var effect = branch.Effects[effectIndex];
                                                    var localEffectIndex = effectIndex;
                                                    <div class="critical-editor-chip-card">
                                                        <div class="critical-editor-chip-preview">
                                                            <AffixBadgeList Effects="@BuildSinglePreviewEffect(effect)" />
                                                            <span class="critical-editor-chip-name">@GetEffectLabel(effect)</span>
                                                        </div>
                                                        <button type="button" class="btn btn-link" @onclick="() => RemoveBranchEffect(branch, localEffectIndex)">Remove</button>
                                                    </div>
                                                }
                                            </div>

                                            @for (var effectIndex = 0; effectIndex < branch.Effects.Count; effectIndex++)
                                            {
                                                var effect = branch.Effects[effectIndex];
                                                <div class="critical-editor-card nested">
                                                    <div class="critical-editor-card-header">
                                                        <strong>@GetEffectLabel(effect)</strong>
                                                    </div>
                                                    @EffectFields(effect)
                                                </div>
                                            }
                                        }
                                    </div>
                                </div>
                            }
                        }
                    </section>

                    <section class="critical-editor-section critical-editor-diagnostics-section">
                        <details class="critical-editor-advanced">
                            <summary class="critical-editor-advanced-summary">
                                <span>Advanced Diagnostics</span>
                                <span class="critical-editor-advanced-meta">@GetAdvancedSummary(Model)</span>
                            </summary>

                            <div class="critical-editor-advanced-body">
                                <div class="critical-editor-card nested">
                                    <div class="critical-editor-card-header">
                                        <div>
                                            <strong>Parser Metadata</strong>
                                            <p class="muted critical-editor-inline-copy">Last loaded or re-parsed parser result.</p>
                                        </div>
                                    </div>

                                    <dl class="critical-editor-diagnostic-grid">
                                        <div>
                                            <dt>Parse Status</dt>
                                            <dd>@Model.ParseStatus</dd>
                                        </div>
                                        <div>
                                            <dt>Raw Affix Text</dt>
                                            <dd>@(string.IsNullOrWhiteSpace(Model.RawAffixText) ? "—" : Model.RawAffixText)</dd>
                                        </div>
                                    </dl>

                                    @if (Model.ValidationMessages.Count > 0)
                                    {
                                        <div class="critical-editor-validation-list">
                                            @foreach (var message in Model.ValidationMessages)
                                            {
                                                <p class="critical-editor-validation-item">@message</p>
                                            }
                                        </div>
                                    }

                                    <div class="field-shell">
                                        <label>Parsed Effects JSON</label>
                                        <pre class="critical-editor-diagnostic-block">@FormatJson(Model.ParsedJson)</pre>
                                    </div>
                                </div>

                                @{
                                    var effectMetadata = GetEffectMetadataRows(Model);
                                }

                                @if (effectMetadata.Count > 0)
                                {
                                    <div class="critical-editor-card nested">
                                        <div class="critical-editor-card-header">
                                            <div>
                                                <strong>Effect Source Metadata</strong>
                                                <p class="muted critical-editor-inline-copy">Stored source markers and labels for the current effect list.</p>
                                            </div>
                                        </div>

                                        <div class="critical-editor-diagnostic-list">
                                            @foreach (var entry in effectMetadata)
                                            {
                                                <div class="critical-editor-diagnostic-item">
                                                    <div>
                                                        <strong>@entry.Scope</strong>
                                                        <p class="muted critical-editor-inline-copy">@entry.EffectLabel</p>
                                                    </div>
                                                    <div class="critical-editor-diagnostic-values">
                                                        <span><strong>Type:</strong> @entry.SourceType</span>
                                                        <span><strong>Text:</strong> @(string.IsNullOrWhiteSpace(entry.SourceText) ? "—" : entry.SourceText)</span>
                                                    </div>
                                                </div>
                                            }
                                        </div>
                                    </div>
                                }

                                <div class="critical-editor-card nested">
                                    <div class="critical-editor-card-header">
                                        <div>
                                            <strong>Current Save Payload</strong>
                                            <p class="muted critical-editor-inline-copy">Request built from the visible editor state, including generated branch internals.</p>
                                        </div>
                                    </div>
                                    <pre class="critical-editor-diagnostic-block">@BuildCurrentSavePayloadJson(Model)</pre>
                                </div>
                            </div>
                        </details>
                    </section>
                </div>

                <footer class="critical-editor-footer">
                    <button type="button" class="btn btn-link" @onclick="OnClose" disabled="@IsSaving">Cancel</button>
                    <button type="submit" class="btn-ritual" disabled="@IsSaving">
                        @(IsSaving ? "Saving..." : "Save Cell")
                    </button>
                </footer>
            </EditForm>
        }
    </div>
</div>

@code {
    [Parameter, EditorRequired]
    public CriticalCellEditorModel? Model { get; set; }

    [Parameter]
    public bool IsLoading { get; set; }

    [Parameter]
    public bool IsReparsing { get; set; }

    [Parameter]
    public bool IsSaving { get; set; }

    [Parameter]
    public string? LoadErrorMessage { get; set; }

    [Parameter]
    public string? ReparseErrorMessage { get; set; }

    [Parameter]
    public string? SaveErrorMessage { get; set; }

    [Parameter, EditorRequired]
    public EventCallback OnClose { get; set; }

    [Parameter, EditorRequired]
    public EventCallback OnReparse { get; set; }

    [Parameter, EditorRequired]
    public EventCallback OnSave { get; set; }

    private static readonly JsonSerializerOptions DiagnosticJsonOptions = new()
    {
        WriteIndented = true
    };

    private async Task HandleBackdropClicked()
    {
        await OnClose.InvokeAsync();
    }

    private async Task HandleSubmitAsync(EditContext _)
    {
        await OnSave.InvokeAsync();
    }

    private void AddBaseEffect()
    {
        Model?.Effects.Add(CreateDefaultEffectModel());
    }

    private void RemoveBaseEffect(int index)
    {
        if (Model is null || index < 0 || index >= Model.Effects.Count)
        {
            return;
        }

        Model.Effects.RemoveAt(index);
    }

    private void AddBranch()
    {
        if (Model is null)
        {
            return;
        }

        Model.Branches.Add(new CriticalBranchEditorModel
        {
            ConditionText = $"Condition {Model.Branches.Count + 1}",
            SortOrder = Model.Branches.Count + 1
        });
    }

    private void RemoveBranch(int index)
    {
        if (Model is null || index < 0 || index >= Model.Branches.Count)
        {
            return;
        }

        Model.Branches.RemoveAt(index);
    }

    private static void AddBranchEffect(CriticalBranchEditorModel branch)
    {
        branch.Effects.Add(CreateDefaultEffectModel());
    }

    private static void RemoveBranchEffect(CriticalBranchEditorModel branch, int index)
    {
        if (index < 0 || index >= branch.Effects.Count)
        {
            return;
        }

        branch.Effects.RemoveAt(index);
    }

    private static CriticalEffectEditorModel CreateDefaultEffectModel() =>
        new()
        {
            EffectCode = CriticalEffectCodes.DirectHits,
            SourceType = "symbol"
        };

    private static string GetBranchTitle(CriticalBranchEditorModel branch, int index) =>
        string.IsNullOrWhiteSpace(branch.ConditionText)
            ? $"Condition {index + 1}"
            : branch.ConditionText;

    private static string GetEffectLabel(CriticalEffectEditorModel effect)
    {
        if (AffixDisplayMap.TryGet(effect.EffectCode, out var info))
        {
            return info.Label;
        }

        return string.IsNullOrWhiteSpace(effect.EffectCode) ? "Custom Effect" : effect.EffectCode;
    }

    private static IEnumerable<KeyValuePair<string, string>> GetEffectOptions(string? currentCode)
    {
        if (!string.IsNullOrWhiteSpace(currentCode) && !AffixDisplayMap.Entries.ContainsKey(currentCode))
        {
            yield return new KeyValuePair<string, string>(currentCode, currentCode);
        }

        foreach (var entry in AffixDisplayMap.Entries.OrderBy(item => item.Value.Label))
        {
            yield return new KeyValuePair<string, string>(entry.Key, entry.Value.Label);
        }
    }

    private static void HandleEffectCodeChanged(CriticalEffectEditorModel effect, string? newCode)
    {
        var normalizedCode = newCode?.Trim() ?? string.Empty;
        if (string.Equals(effect.EffectCode, normalizedCode, StringComparison.Ordinal))
        {
            return;
        }

        effect.EffectCode = normalizedCode;
        effect.Target = null;
        effect.ValueInteger = null;
        effect.ValueDecimal = null;
        effect.ValueExpression = null;
        effect.DurationRounds = null;
        effect.PerRound = null;
        effect.Modifier = null;
        effect.BodyPart = null;
        effect.IsPermanent = false;
        effect.SourceText = null;
        effect.SourceType = AffixDisplayMap.TryGet(effect.EffectCode, out _) ? "symbol" : "manual";
    }

    private static string GetAdvancedSummary(CriticalCellEditorModel model)
    {
        var noteCount = model.ValidationMessages.Count;
        return noteCount == 0 ? "Parser metadata and save payload" : $"{noteCount} parser note{(noteCount == 1 ? string.Empty : "s")}";
    }

    private static string GetParserNoteSummary(int noteCount) =>
        noteCount == 1
            ? "1 parser note is available under Advanced Diagnostics."
            : $"{noteCount} parser notes are available under Advanced Diagnostics.";

    private static string FormatJson(string json)
    {
        if (string.IsNullOrWhiteSpace(json))
        {
            return "{}";
        }

        try
        {
            using var document = JsonDocument.Parse(json);
            return JsonSerializer.Serialize(document.RootElement, DiagnosticJsonOptions);
        }
        catch (JsonException)
        {
            return json.Trim();
        }
    }

    private static string BuildCurrentSavePayloadJson(CriticalCellEditorModel model) =>
        JsonSerializer.Serialize(model.ToRequest(), DiagnosticJsonOptions);

    private static List<(string Scope, string EffectLabel, string SourceType, string? SourceText)> GetEffectMetadataRows(CriticalCellEditorModel model)
    {
        var rows = new List<(string Scope, string EffectLabel, string SourceType, string? SourceText)>();

        foreach (var effect in model.Effects)
        {
            if (ShouldIncludeEffectMetadata(effect))
            {
                rows.Add(("Base Result", GetEffectLabel(effect), effect.SourceType, effect.SourceText));
            }
        }

        foreach (var branch in model.Branches.OrderBy(item => item.SortOrder))
        {
            var scope = string.IsNullOrWhiteSpace(branch.ConditionText) ? "Condition" : branch.ConditionText.Trim();
            foreach (var effect in branch.Effects)
            {
                if (ShouldIncludeEffectMetadata(effect))
                {
                    rows.Add((scope, GetEffectLabel(effect), effect.SourceType, effect.SourceText));
                }
            }
        }

        return rows;
    }

    private static bool ShouldIncludeEffectMetadata(CriticalEffectEditorModel effect) =>
        !string.IsNullOrWhiteSpace(effect.SourceText) ||
        !string.IsNullOrWhiteSpace(effect.SourceType);

    private static IReadOnlyList<CriticalEffectLookupResponse> BuildPreviewEffects(IEnumerable<CriticalEffectEditorModel> effects) =>
        effects.Select(CreatePreviewEffect).ToList();

    private static IReadOnlyList<CriticalEffectLookupResponse> BuildSinglePreviewEffect(CriticalEffectEditorModel effect) =>
        [CreatePreviewEffect(effect)];

    private static IReadOnlyList<CriticalBranchLookupResponse> BuildPreviewBranches(IEnumerable<CriticalBranchEditorModel> branches) =>
        branches
            .OrderBy(branch => branch.SortOrder)
            .Select(branch => new CriticalBranchLookupResponse(
                branch.BranchKind,
                branch.ConditionKey,
                branch.ConditionText,
                branch.DescriptionText,
                branch.RawAffixText,
                BuildPreviewEffects(branch.Effects),
                branch.RawText,
                branch.SortOrder))
            .ToList();

    private static CriticalEffectLookupResponse CreatePreviewEffect(CriticalEffectEditorModel effect) =>
        new(
            effect.EffectCode,
            effect.Target,
            effect.ValueInteger,
            effect.ValueExpression,
            effect.DurationRounds,
            effect.PerRound,
            effect.Modifier,
            effect.BodyPart,
            effect.IsPermanent,
            effect.SourceType,
            effect.SourceText);
}

@functions {
    private RenderFragment EffectFields(CriticalEffectEditorModel effect) => @<div class="critical-editor-effect-fields">
        <div class="form-grid critical-editor-effect-grid">
            <div class="field-shell">
                <label>Effect</label>
                <select class="input-shell" value="@effect.EffectCode" @onchange="args => HandleEffectCodeChanged(effect, args.Value?.ToString())">
                    @foreach (var option in GetEffectOptions(effect.EffectCode))
                    {
                        <option value="@option.Key">@option.Value</option>
                    }
                </select>
            </div>
            @switch (effect.EffectCode)
            {
                case CriticalEffectCodes.DirectHits:
                    <div class="field-shell">
                        <label>Hits</label>
                        <InputNumber TValue="int?" class="input-shell" @bind-Value="effect.ValueInteger" />
                    </div>
                    break;
                case CriticalEffectCodes.StunnedRounds:
                case CriticalEffectCodes.MustParryRounds:
                case CriticalEffectCodes.NoParryRounds:
                    <div class="field-shell">
                        <label>Rounds</label>
                        <InputNumber TValue="int?" class="input-shell" @bind-Value="effect.DurationRounds" />
                    </div>
                    break;
                case CriticalEffectCodes.BleedPerRound:
                    <div class="field-shell">
                        <label>Bleed / Round</label>
                        <InputNumber TValue="int?" class="input-shell" @bind-Value="effect.PerRound" />
                    </div>
                    break;
                case CriticalEffectCodes.FoePenalty:
                case CriticalEffectCodes.AttackerBonusNextRound:
                    <div class="field-shell">
                        <label>Modifier</label>
                        <InputNumber TValue="int?" class="input-shell" @bind-Value="effect.Modifier" />
                    </div>
                    break;
                case CriticalEffectCodes.PowerPointModifier:
                    <div class="field-shell">
                        <label>Expression</label>
                        <InputText class="input-shell" @bind-Value="effect.ValueExpression" />
                    </div>
                    break;
                default:
                    <div class="field-shell">
                        <label>Display Text</label>
                        <InputText class="input-shell" @bind-Value="effect.SourceText" />
                    </div>
                    break;
            }
            @if (!string.IsNullOrWhiteSpace(effect.BodyPart))
            {
                <div class="field-shell">
                    <label>Body Part</label>
                    <InputText class="input-shell" @bind-Value="effect.BodyPart" />
                </div>
            }
            @if (!string.IsNullOrWhiteSpace(effect.Target))
            {
                <div class="field-shell">
                    <label>Target</label>
                    <InputText class="input-shell" @bind-Value="effect.Target" />
                </div>
            }
        </div>
        <label class="critical-editor-checkbox">
            <InputCheckbox class="form-check-input" @bind-Value="effect.IsPermanent" />
            <span>Permanent</span>
        </label>
    </div>;
}
