#nullable enable

namespace MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

/// <summary>
/// Marker for trusted, scene-specific data created by the native DB layer.
/// Web messages never deserialize into these contracts.
/// </summary>
public interface ILegacySceneData
{
}

/// <summary>
/// Converts one explicit scene DTO into a deterministic COM-neutral mutation sequence.
/// </summary>
public interface ILegacySceneMutationBuilder<in TData>
    where TData : ILegacySceneData
{
    string BuilderKey { get; }

    IReadOnlyList<PlayoutMutation> Build(TData data);
}

public sealed class LegacySceneDataException : Exception
{
    public LegacySceneDataException(string message)
        : base(message)
    {
    }
}

internal static class LegacySceneBuilderGuard
{
    public static T NotNull<T>(T? value, string name)
        where T : class => value ?? throw new LegacySceneDataException(
            $"Scene data field '{name}' is required.");

    public static string Text(string? value, string name, bool allowEmpty = false)
    {
        if (value is null || value.Length > 4_096 || value.Any(char.IsControl) ||
            (!allowEmpty && string.IsNullOrWhiteSpace(value)))
        {
            throw new LegacySceneDataException(
                $"Scene data field '{name}' is invalid.");
        }

        return value;
    }

    public static IReadOnlyList<T> Count<T>(
        IReadOnlyList<T>? values,
        int expected,
        string name)
    {
        if (values is null || values.Count != expected)
        {
            throw new LegacySceneDataException(
                $"Scene data field '{name}' must contain exactly {expected} items.");
        }

        return values;
    }

    public static IReadOnlyList<T> Range<T>(
        IReadOnlyList<T>? values,
        int minimum,
        int maximum,
        string name)
    {
        if (values is null || values.Count < minimum || values.Count > maximum)
        {
            throw new LegacySceneDataException(
                $"Scene data field '{name}' must contain between {minimum} and {maximum} items.");
        }

        return values;
    }
}
