using System.Linq;
using NeonSprawl.Server.Game.PositionState;

namespace NeonSprawl.Server.Game.Interaction;

/// <summary>Prototype id → world anchor + reach + kind. Keys are lowercase; lookup after trim + case fold (NS-18).</summary>
public static class PrototypeInteractableRegistry
{
    /// <summary>Canonical lowercase id for the center prototype row (NEO-9).</summary>
    public const string PrototypeTerminalId = "prototype_terminal";

    /// <summary>Second stub row for multi-entity projection (NEO-25).</summary>
    public const string PrototypeResourceNodeAlphaId = "prototype_resource_node_alpha";

    /// <summary><see cref="PrototypeInteractableEntry.Kind"/> for gather-anchor nodes (NEO-41).</summary>
    public const string ResourceNodeKind = "resource_node";

    /// <summary>Source-of-truth anchor and radius; client discovers via <c>GET /game/world/interactables</c> (NEO-25).</summary>
    public static readonly PrototypeInteractableEntry PrototypeTerminal = new(0, 0.5, 0, 3.0, "terminal");

    /// <summary>+X / −Z open floor (avoids overlap with scene <c>Obstacle</c> at ~(6,1,5)); same radius as terminal.</summary>
    public static readonly PrototypeInteractableEntry PrototypeResourceNodeAlpha = new(12, 0.5, -6, 3.0, ResourceNodeKind);

    private static readonly Dictionary<string, PrototypeInteractableEntry> ById = new(StringComparer.Ordinal)
    {
        [PrototypeTerminalId] = PrototypeTerminal,
        [PrototypeResourceNodeAlphaId] = PrototypeResourceNodeAlpha,
    };

    public static bool TryGet(string interactableIdLowercase, out PrototypeInteractableEntry entry) =>
        ById.TryGetValue(interactableIdLowercase, out entry);

    /// <summary>Ascending <c>interactableId</c> for stable JSON and tests.</summary>
    public static IReadOnlyList<InteractableDescriptorJson> GetOrderedDescriptors()
    {
        var list = new List<InteractableDescriptorJson>(ById.Count);
        foreach (var kv in ById.OrderBy(static x => x.Key, StringComparer.Ordinal))
        {
            var e = kv.Value;
            list.Add(
                new InteractableDescriptorJson
                {
                    InteractableId = kv.Key,
                    Kind = e.Kind,
                    Anchor = new PositionVector
                    {
                        X = e.X,
                        Y = e.Y,
                        Z = e.Z,
                    },
                    InteractionRadius = e.InteractionRadius,
                });
        }

        return list;
    }
}

/// <param name="InteractionRadius">Horizontal reach on X/Z; inclusive boundary.</param>
/// <param name="Kind">Stable machine category for clients and future rules (NEO-25).</param>
public readonly record struct PrototypeInteractableEntry(
    double X,
    double Y,
    double Z,
    double InteractionRadius,
    string Kind);
