using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;
using RpgRoller.Contracts;

namespace RpgRoller.Components.Pages.HomeControls;

[ExcludeFromCodeCoverage]
public partial class SkillFormModal
{
    protected override void OnParametersSet()
    {
        if (!Visible || FormVersion == AppliedFormVersion)
            return;

        FormState.Model.Name = InitialModel.Name;
        FormState.Model.RulesetId = RulesetId;
        FormState.Model.DiceRollDefinition = InitialModel.DiceRollDefinition;
        FormState.Model.SkillGroupId = InitialModel.SkillGroupId;
        FormState.Model.WildDice = InitialModel.WildDice;
        FormState.Model.AllowFumble = InitialModel.AllowFumble;
        FormState.Model.FumbleRange = InitialModel.FumbleRange;
        FormState.Model.RolemasterAutoRetry = InitialModel.RolemasterAutoRetry;
        SynchronizeRulesetSpecificFields();
        FormState.ResetValidation();
        AppliedFormVersion = FormVersion;
        PendingNameFocus = AutoFocusName;
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!Visible || !PendingNameFocus)
            return;

        PendingNameFocus = false;
        await NameInputElement.FocusAsync();
    }

    private async Task SubmitAsync()
    {
        FormState.ResetValidation();

        if (string.IsNullOrWhiteSpace(FormState.Model.Name))
            FormState.Errors["name"] = "Skill name is required.";

        if (string.IsNullOrWhiteSpace(FormState.Model.DiceRollDefinition))
            FormState.Errors["diceRollDefinition"] = "Expression is required.";

        if (IsD6Ruleset && FormState.Model.WildDice < 1)
            FormState.Errors["wildDice"] = "D6 skills require at least one wild die.";

        if (IsRolemasterRuleset)
        {
            if (IsRolemasterOpenEndedSelected && !FormState.Model.FumbleRange.HasValue)
                FormState.Errors["fumbleRange"] = "Open-ended Rolemaster skills require a fumble range.";
        }
        else
        {
            FormState.Model.FumbleRange = null;
            FormState.Model.RolemasterAutoRetry = false;
        }

        if (!IsD6Ruleset)
        {
            FormState.Model.WildDice = 0;
            FormState.Model.AllowFumble = false;
        }

        Guid? skillGroupId = null;
        if (!string.IsNullOrWhiteSpace(FormState.Model.SkillGroupId))
        {
            if (!Guid.TryParse(FormState.Model.SkillGroupId, out var parsedSkillGroupId))
                FormState.Errors["skillGroupId"] = "Skill group is invalid.";
            else
                skillGroupId = parsedSkillGroupId;
        }

        if (FormState.Errors.Count > 0)
        {
            FormState.ErrorMessage = "Resolve validation issues before submitting.";
            return;
        }

        IsSubmitting = true;
        try
        {
            SkillSummary skill;
            if (EditingSkillId.HasValue)
                skill = await ApiClient.RequestAsync<SkillSummary>("PUT", $"/api/skills/{EditingSkillId.Value}",
                    new UpdateSkillRequest(FormState.Model.Name.Trim(), FormState.Model.DiceRollDefinition.Trim(),
                        FormState.Model.WildDice, FormState.Model.AllowFumble, skillGroupId,
                        FormState.Model.FumbleRange, FormState.Model.RolemasterAutoRetry));
            else
            {
                if (!SelectedCharacterId.HasValue)
                {
                    FormState.ErrorMessage = "Select a character first.";
                    return;
                }

                skill = await ApiClient.RequestAsync<SkillSummary>("POST",
                    $"/api/characters/{SelectedCharacterId.Value}/skills",
                    new CreateSkillRequest(FormState.Model.Name.Trim(), FormState.Model.DiceRollDefinition.Trim(),
                        FormState.Model.WildDice, FormState.Model.AllowFumble, skillGroupId,
                        FormState.Model.FumbleRange, FormState.Model.RolemasterAutoRetry));
            }

            await SkillSaved.InvokeAsync(skill.Id);
        }
        catch (ApiRequestException ex)
        {
            FormState.ErrorMessage = ex.Message;
        }
        finally
        {
            IsSubmitting = false;
        }
    }

    private void OnExpressionChanged(ChangeEventArgs args)
    {
        FormState.Model.DiceRollDefinition = args.Value?.ToString() ?? string.Empty;
        if (IsRolemasterRuleset)
            NormalizeRolemasterFumbleRange();
    }

    private void SynchronizeRulesetSpecificFields()
    {
        if (!IsRolemasterRuleset)
        {
            FormState.Model.RolemasterAutoRetry = false;
            return;
        }

        NormalizeRolemasterFumbleRange();
    }

    private void NormalizeRolemasterFumbleRange()
    {
        if (!IsRolemasterRuleset)
        {
            FormState.Model.FumbleRange = null;
            return;
        }

        if (IsRolemasterOpenEndedSelected)
        {
            FormState.Model.FumbleRange ??= 5;
            return;
        }

        FormState.Model.FumbleRange = null;
        FormState.Model.RolemasterAutoRetry = false;
    }

    private bool IsD6Ruleset => RulesetFormHelpers.IsD6(RulesetId);
    private bool IsRolemasterRuleset => RulesetFormHelpers.IsRolemaster(RulesetId);

    private bool IsRolemasterOpenEndedSelected =>
        RulesetFormHelpers.IsRolemasterOpenEndedExpression(FormState.Model.DiceRollDefinition);

    private string ExpressionHelpText => IsRolemasterRuleset
        ? $"{RulesetFormHelpers.RolemasterExampleText()}. Negative modifiers are allowed."
        : "Enter the dice expression used for this skill.";

    [Inject] private RpgRollerApiClient ApiClient { get; set; } = null!;

    private FormState<SkillFormModel> FormState { get; } = new();
    private int AppliedFormVersion { get; set; } = -1;
    private bool IsSubmitting { get; set; }
    private bool PendingNameFocus { get; set; }
    private ElementReference NameInputElement { get; set; }

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

    [Parameter] public string RulesetId { get; set; } = string.Empty;

    [Parameter] public string Title { get; set; } = "Skill";

    [Parameter] public string SubmitLabel { get; set; } = "Save";

    [Parameter] public string NameInputId { get; set; } = "skill-name";

    [Parameter] public string ExpressionInputId { get; set; } = "skill-expression";

    [Parameter] public string SkillGroupInputId { get; set; } = "skill-group";

    [Parameter] public string WildDiceInputId { get; set; } = "skill-wild";

    [Parameter] public string AllowFumbleInputId { get; set; } = "skill-fumble";

    [Parameter] public string FumbleRangeInputId { get; set; } = "skill-fumble-range";

    [Parameter] public SkillFormModel InitialModel { get; set; } = new();

    [Parameter] public int FormVersion { get; set; }

    [Parameter] public Guid? SelectedCharacterId { get; set; }

    [Parameter] public Guid? EditingSkillId { get; set; }

    [Parameter] public IReadOnlyList<CharacterSheetSkillGroup> AvailableSkillGroups { get; set; } = [];

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

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

    [Parameter] public EventCallback<Guid> SkillSaved { get; set; }

    [Parameter] public EventCallback CancelRequested { get; set; }
}