using Theriapolis.Core.Data;

namespace Theriapolis.Core.Rules.Character;

/// <summary>
/// Phase 6.5 M2 — given a character's <see cref="ClassDef"/> + a chosen
/// <c>subclassId</c>, look up the subclass-feature ids unlocked at a
/// specific level. Used by <see cref="LevelUpFlow.Compute"/> to populate
/// <see cref="LevelUpResult.SubclassFeaturesUnlocked"/>.
///
/// The resolver does NOT mutate state — it's a pure lookup. The
/// <see cref="FeatureProcessor"/> takes the resulting feature ids and
/// applies their mechanical effects at combat-resolution time.
/// </summary>
public static class SubclassResolver
{
    /// <summary>
    /// Look up a subclass def by id from a content collection. Returns
    /// null if the id is empty or unknown — callers should treat that as
    /// "no subclass picked yet" (pre-L3) or "subclass content missing"
    /// (data error, log it).
    /// </summary>
    public static SubclassDef? TryFindSubclass(
        IReadOnlyDictionary<string, SubclassDef> subclasses,
        string? subclassId)
    {
        if (string.IsNullOrEmpty(subclassId)) return null;
        return subclasses.TryGetValue(subclassId, out var def) ? def : null;
    }

    /// <summary>
    /// Feature ids unlocked by the chosen subclass at <paramref name="level"/>.
    /// Returns an empty array if no subclass is picked, the subclass def is
    /// missing, or the level has no entry in <see cref="SubclassDef.LevelFeatures"/>.
    /// </summary>
    public static string[] UnlockedFeaturesAt(
        IReadOnlyDictionary<string, SubclassDef> subclasses,
        string? subclassId,
        int level)
    {
        var def = TryFindSubclass(subclasses, subclassId);
        if (def is null) return Array.Empty<string>();
        foreach (var entry in def.LevelFeatures)
            if (entry.Level == level)
                return entry.Features ?? Array.Empty<string>();
        return Array.Empty<string>();
    }

    /// <summary>
    /// Resolve a feature description (for display in the level-up screen
    /// and combat HUD tooltips). Looks first in the subclass's
    /// <see cref="SubclassDef.FeatureDefinitions"/>, then falls through to
    /// the parent class's
    /// <see cref="ClassDef.FeatureDefinitions"/> (in case the feature id is
    /// shared — e.g. <c>asi</c>, <c>extra_attack</c>). Returns null if neither
    /// has it.
    /// </summary>
    public static ClassFeatureDef? ResolveFeatureDef(
        ClassDef classDef,
        SubclassDef? subclass,
        string featureId)
    {
        if (subclass is not null
            && subclass.FeatureDefinitions.TryGetValue(featureId, out var sdef))
            return sdef;
        if (classDef.FeatureDefinitions.TryGetValue(featureId, out var cdef))
            return cdef;
        return null;
    }
}
