using System.Text.Json.Serialization;

namespace Theriapolis.Core.Data;

/// <summary>
/// Phase 6 M4 — JSON-loaded quest definition. A quest is a directed graph
/// of steps; the engine starts at <see cref="EntryStep"/>, evaluates each
/// active step's <see cref="QuestStepDef.TriggerConditions"/> per tick,
/// and runs <see cref="QuestStepDef.OnEnter"/> + <see cref="QuestStepDef.Outcomes"/>
/// when the step fires.
///
/// Author convention: one tree per file in
/// <c>Content/Data/quests/*.json</c>. <see cref="Id"/> matches the
/// filename. Step ids are strings local to the tree.
/// </summary>
public sealed record QuestDef
{
    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    [JsonPropertyName("title")]
    public string Title { get; init; } = "";

    [JsonPropertyName("description")]
    public string Description { get; init; } = "";

    /// <summary>True when the quest doesn't appear in the journal until first activation (Maw discovery, etc.).</summary>
    [JsonPropertyName("hidden")]
    public bool Hidden { get; init; } = false;

    /// <summary>Step id the engine activates on quest start.</summary>
    [JsonPropertyName("entry_step")]
    public string EntryStep { get; init; } = "";

    [JsonPropertyName("steps")]
    public QuestStepDef[] Steps { get; init; } = System.Array.Empty<QuestStepDef>();

    /// <summary>
    /// Optional: triggers that auto-start this quest. The engine checks
    /// these against world state on every tick; when any fires, the quest
    /// activates at <see cref="EntryStep"/>. Empty = manual-start (e.g.
    /// dialogue's <c>start_quest</c> effect).
    /// </summary>
    [JsonPropertyName("auto_start_when")]
    public QuestConditionDef[] AutoStartWhen { get; init; } = System.Array.Empty<QuestConditionDef>();
}

public sealed record QuestStepDef
{
    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    [JsonPropertyName("title")]
    public string Title { get; init; } = "";

    [JsonPropertyName("description")]
    public string Description { get; init; } = "";

    /// <summary>Optional waypoint hint — anchor or role tag the player should head toward.</summary>
    [JsonPropertyName("waypoint")]
    public string Waypoint { get; init; } = "";

    /// <summary>Conditions that fire this step's onEnter + outcomes when ALL true.</summary>
    [JsonPropertyName("trigger_conditions")]
    public QuestConditionDef[] TriggerConditions { get; init; } = System.Array.Empty<QuestConditionDef>();

    /// <summary>Effects applied once when the step fires.</summary>
    [JsonPropertyName("on_enter")]
    public QuestEffectDef[] OnEnter { get; init; } = System.Array.Empty<QuestEffectDef>();

    /// <summary>Step ids this step transitions into (any one is selected via outcome conditions).</summary>
    [JsonPropertyName("outcomes")]
    public QuestOutcomeDef[] Outcomes { get; init; } = System.Array.Empty<QuestOutcomeDef>();

    /// <summary>True if reaching this step completes the quest (success).</summary>
    [JsonPropertyName("completes_quest")]
    public bool CompletesQuest { get; init; } = false;

    /// <summary>True if reaching this step fails the quest.</summary>
    [JsonPropertyName("fails_quest")]
    public bool FailsQuest { get; init; } = false;
}

public sealed record QuestOutcomeDef
{
    /// <summary>Step id to transition to. <c>"&lt;end&gt;"</c> closes the quest.</summary>
    [JsonPropertyName("next")]
    public string Next { get; init; } = "";

    /// <summary>Conditions for THIS outcome to be selected. Empty = always.</summary>
    [JsonPropertyName("when")]
    public QuestConditionDef[] When { get; init; } = System.Array.Empty<QuestConditionDef>();

    [JsonPropertyName("effects")]
    public QuestEffectDef[] Effects { get; init; } = System.Array.Empty<QuestEffectDef>();
}

/// <summary>Trigger / outcome predicate.</summary>
public sealed record QuestConditionDef
{
    /// <summary>
    /// One of: "flag_set", "flag_clear", "flag_at_least", "enter_anchor",
    /// "enter_role_proximity", "npc_dead", "npc_alive", "time_elapsed_seconds",
    /// "rep_at_least", "rep_below", "has_item", "not_has_item",
    /// "quest_complete", "quest_active", "dialogue_choice".
    /// </summary>
    [JsonPropertyName("kind")]
    public string Kind { get; init; } = "";

    [JsonPropertyName("flag")]
    public string Flag { get; init; } = "";

    [JsonPropertyName("anchor")]
    public string Anchor { get; init; } = "";

    [JsonPropertyName("role")]
    public string Role { get; init; } = "";

    [JsonPropertyName("npc")]
    public string Npc { get; init; } = "";

    [JsonPropertyName("faction")]
    public string Faction { get; init; } = "";

    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    [JsonPropertyName("quest")]
    public string Quest { get; init; } = "";

    [JsonPropertyName("value")]
    public int Value { get; init; }

    [JsonPropertyName("seconds")]
    public long Seconds { get; init; }
}

/// <summary>Quest-step side effect.</summary>
public sealed record QuestEffectDef
{
    /// <summary>
    /// One of: "set_flag", "clear_flag", "give_item", "take_item",
    /// "give_xp", "rep_event", "spawn_npc", "despawn_npc",
    /// "start_quest", "end_quest", "fail_quest".
    /// </summary>
    [JsonPropertyName("kind")]
    public string Kind { get; init; } = "";

    [JsonPropertyName("flag")]
    public string Flag { get; init; } = "";

    [JsonPropertyName("value")]
    public int Value { get; init; } = 1;

    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    [JsonPropertyName("qty")]
    public int Qty { get; init; } = 1;

    [JsonPropertyName("xp")]
    public int Xp { get; init; }

    [JsonPropertyName("event")]
    public DialogueRepEventDef? Event { get; init; }

    [JsonPropertyName("quest")]
    public string Quest { get; init; } = "";

    /// <summary>For spawn_npc: resident template id (named takes precedence).</summary>
    [JsonPropertyName("template")]
    public string Template { get; init; } = "";

    /// <summary>For spawn_npc/despawn_npc: which named role tag is being mutated.</summary>
    [JsonPropertyName("role")]
    public string Role { get; init; } = "";
}
