using System.Text.Json.Serialization;

namespace Theriapolis.Core.Data;

/// <summary>
/// Phase 6 M0 — describes how to lay buildings inside a settlement footprint.
///
/// Two flavours:
/// 1. **Hand-authored preset** — `kind == "preset"`. The <see cref="Buildings"/>
///    array specifies each building by template id and offset from the
///    settlement centre. Used for narrative anchors (Millhaven, Thornfield).
/// 2. **Procedural rule-based** — `kind == "procedural"`. The <see cref="Roles"/>
///    array specifies a mix of category weights ("inn" 0.1, "shop" 0.3,
///    "house" 0.6) and a target building count; <see cref="World.Settlements.SettlementStamper"/>
///    rolls templates from the matching categories until the target count is
///    met or no more building slots fit inside the plaza radius.
///
/// Bound to a settlement either by anchor name (preset) or by tier
/// (procedural fallback for any non-anchor settlement of that tier).
/// </summary>
public sealed record SettlementLayoutDef
{
    [JsonPropertyName("id")]
    public string Id { get; init; } = "";

    /// <summary>"preset" or "procedural".</summary>
    [JsonPropertyName("kind")]
    public string Kind { get; init; } = "procedural";

    /// <summary>For preset layouts: matches Settlement.Anchor.ToString() (e.g. "Millhaven").</summary>
    [JsonPropertyName("anchor")]
    public string Anchor { get; init; } = "";

    /// <summary>For procedural layouts: matches Settlement.Tier (1–5).</summary>
    [JsonPropertyName("tier")]
    public int Tier { get; init; } = 0;

    // ── Preset payload ─────────────────────────────────────────────────────

    /// <summary>Building placements for preset layouts. Ignored when kind == "procedural".</summary>
    [JsonPropertyName("buildings")]
    public SettlementBuildingPlacement[] Buildings { get; init; } = Array.Empty<SettlementBuildingPlacement>();

    // ── Procedural payload ─────────────────────────────────────────────────

    /// <summary>Category mix for procedural layouts. Ignored when kind == "preset".</summary>
    [JsonPropertyName("category_weights")]
    public Dictionary<string, float> CategoryWeights { get; init; } = new();

    /// <summary>Target building count for procedural layouts.</summary>
    [JsonPropertyName("target_building_count")]
    public int TargetBuildingCount { get; init; } = 5;

    /// <summary>
    /// Plaza radius in tactical tiles to search for building slots (procedural).
    /// If 0, the stamper picks one based on tier.
    /// </summary>
    [JsonPropertyName("plaza_radius_tiles")]
    public int PlazaRadiusTiles { get; init; } = 0;
}

public sealed record SettlementBuildingPlacement
{
    /// <summary>BuildingTemplateDef.Id to stamp.</summary>
    [JsonPropertyName("template")]
    public string Template { get; init; } = "";

    /// <summary>
    /// Offset from settlement centre in tactical tiles. (0,0) places the
    /// building's centre on the settlement centre tile.
    /// </summary>
    [JsonPropertyName("offset")]
    public int[] Offset { get; init; } = new[] { 0, 0 };

    /// <summary>
    /// Optional rotation: 0 / 90 / 180 / 270. Phase 6 M0 ignores; reserved
    /// so layouts don't have to be re-authored when rotation lands.
    /// </summary>
    [JsonPropertyName("rotation_deg")]
    public int RotationDeg { get; init; } = 0;

    /// <summary>
    /// Override the role tag for one or more roles in this building. E.g.
    /// the innkeeper template has role "innkeeper"; this preset assigns
    /// it the named role "millhaven.innkeeper" so quest scripts can
    /// reference the specific NPC.
    /// </summary>
    [JsonPropertyName("role_overrides")]
    public Dictionary<string, string> RoleOverrides { get; init; } = new();
}
