// <auto-generated />
#nullable enable

namespace GFramework.Game.Config.Generated;

/// <summary>
///     Auto-generated registration and lookup helpers for schema file 'monster.schema.json'.
///     The helper centralizes table naming, config directory, schema path, and strongly-typed registry access so consumer projects do not need to duplicate the same conventions.
/// </summary>
public static class MonsterConfigBindings
{
    /// <summary>
    ///     Describes one schema property that declares <c>x-gframework-ref-table</c> metadata.
    /// </summary>
    public readonly struct ReferenceMetadata
    {
        /// <summary>
        ///     Initializes one generated cross-table reference descriptor.
        /// </summary>
        /// <param name="displayPath">Schema property path.</param>
        /// <param name="referencedTableName">Referenced runtime table name.</param>
        /// <param name="valueSchemaType">Schema scalar type used by the reference value.</param>
        /// <param name="isCollection">Whether the property stores multiple reference keys.</param>
        public ReferenceMetadata(
            string displayPath,
            string referencedTableName,
            string valueSchemaType,
            bool isCollection)
        {
            DisplayPath = displayPath ?? throw new global::System.ArgumentNullException(nameof(displayPath));
            ReferencedTableName = referencedTableName ?? throw new global::System.ArgumentNullException(nameof(referencedTableName));
            ValueSchemaType = valueSchemaType ?? throw new global::System.ArgumentNullException(nameof(valueSchemaType));
            IsCollection = isCollection;
        }

        /// <summary>
        ///     Gets the schema property path such as <c>dropItems</c> or <c>phases[].monsterId</c>.
        /// </summary>
        public string DisplayPath { get; }

        /// <summary>
        ///     Gets the runtime registration name of the referenced config table.
        /// </summary>
        public string ReferencedTableName { get; }

        /// <summary>
        ///     Gets the schema scalar type used by the referenced key value.
        /// </summary>
        public string ValueSchemaType { get; }

        /// <summary>
        ///     Gets a value indicating whether the property stores multiple reference keys.
        /// </summary>
        public bool IsCollection { get; }
    }

    /// <summary>
    ///     Groups the schema-derived metadata constants so consumer code can reuse one stable entry point.
    /// </summary>
    public static class Metadata
    {
        /// <summary>
        ///     Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.
        /// </summary>
        public const string ConfigDomain = "monster";

        /// <summary>
        ///     Gets the runtime registration name of the generated config table.
        /// </summary>
        public const string TableName = "monster";

        /// <summary>
        ///     Gets the config directory path expected by the generated registration helper.
        /// </summary>
        public const string ConfigRelativePath = "monster";

        /// <summary>
        ///     Gets the schema file path expected by the generated registration helper.
        /// </summary>
        public const string SchemaRelativePath = "schemas/monster.schema.json";
    }

    /// <summary>
    ///     Gets the logical config domain derived from the schema base name. The current runtime convention keeps this value aligned with the generated table name.
    /// </summary>
    public const string ConfigDomain = Metadata.ConfigDomain;

    /// <summary>
    ///     Gets the runtime registration name of the generated config table.
    /// </summary>
    public const string TableName = Metadata.TableName;

    /// <summary>
    ///     Gets the config directory path expected by the generated registration helper.
    /// </summary>
    public const string ConfigRelativePath = Metadata.ConfigRelativePath;

    /// <summary>
    ///     Gets the schema file path expected by the generated registration helper.
    /// </summary>
    public const string SchemaRelativePath = Metadata.SchemaRelativePath;

    /// <summary>
    ///     Serializes one generated config instance to YAML text using the shared runtime naming convention.
    /// </summary>
    /// <param name="config">The generated config instance to serialize.</param>
    /// <returns>YAML text that preserves the shared camelCase field naming convention.</returns>
    /// <exception cref="global::System.ArgumentNullException">Thrown when <paramref name="config"/> is <see langword="null"/>.</exception>
    public static string SerializeToYaml(MonsterConfig config)
    {
        return global::GFramework.Game.Config.YamlConfigTextSerializer.Serialize(config);
    }

    /// <summary>
    ///     Resolves the absolute config directory path by combining the caller-supplied config root with the generated relative directory.
    /// </summary>
    /// <param name="configRootPath">Absolute or workspace-local config root directory.</param>
    /// <returns>The absolute config directory path for the generated table.</returns>
    /// <exception cref="global::System.ArgumentException">Thrown when <paramref name="configRootPath"/> is null, empty, or whitespace.</exception>
    public static string GetConfigDirectoryPath(string configRootPath)
    {
        return GeneratedConfigCatalog.ResolveAbsolutePath(configRootPath, Metadata.ConfigRelativePath);
    }

    /// <summary>
    ///     Resolves the absolute schema file path by combining the caller-supplied config root with the generated relative schema path.
    /// </summary>
    /// <param name="configRootPath">Absolute or workspace-local config root directory.</param>
    /// <returns>The absolute schema file path for the generated table.</returns>
    /// <exception cref="global::System.ArgumentException">Thrown when <paramref name="configRootPath"/> is null, empty, or whitespace.</exception>
    public static string GetSchemaPath(string configRootPath)
    {
        return GeneratedConfigCatalog.ResolveAbsolutePath(configRootPath, Metadata.SchemaRelativePath);
    }

    /// <summary>
    ///     Validates YAML text against the generated schema file located under the supplied config root directory.
    /// </summary>
    /// <param name="configRootPath">Absolute or workspace-local config root directory.</param>
    /// <param name="yamlPath">Logical or absolute YAML path used for diagnostics.</param>
    /// <param name="yamlText">YAML text to validate.</param>
    /// <exception cref="global::System.ArgumentException">Thrown when <paramref name="configRootPath"/> is null, empty, or whitespace.</exception>
    /// <exception cref="global::System.ArgumentNullException">Thrown when <paramref name="yamlPath"/> or <paramref name="yamlText"/> is <see langword="null"/>.</exception>
    /// <exception cref="global::GFramework.Game.Abstractions.Config.ConfigLoadException">Thrown when the generated schema file cannot be loaded or the YAML text fails schema validation.</exception>
    public static void ValidateYaml(string configRootPath, string yamlPath, string yamlText)
    {
        global::GFramework.Game.Config.YamlConfigTextValidator.Validate(
            Metadata.TableName,
            GetSchemaPath(configRootPath),
            yamlPath,
            yamlText);
    }

    /// <summary>
    ///     Asynchronously validates YAML text against the generated schema file located under the supplied config root directory.
    /// </summary>
    /// <param name="configRootPath">Absolute or workspace-local config root directory.</param>
    /// <param name="yamlPath">Logical or absolute YAML path used for diagnostics.</param>
    /// <param name="yamlText">YAML text to validate.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task that represents the asynchronous validation operation.</returns>
    /// <exception cref="global::System.ArgumentException">Thrown when <paramref name="configRootPath"/> is null, empty, or whitespace.</exception>
    /// <exception cref="global::System.ArgumentNullException">Thrown when <paramref name="yamlPath"/> or <paramref name="yamlText"/> is <see langword="null"/>.</exception>
    /// <exception cref="global::GFramework.Game.Abstractions.Config.ConfigLoadException">Thrown when the generated schema file cannot be loaded or the YAML text fails schema validation.</exception>
    public static global::System.Threading.Tasks.Task ValidateYamlAsync(
        string configRootPath,
        string yamlPath,
        string yamlText,
        global::System.Threading.CancellationToken cancellationToken = default)
    {
        return global::GFramework.Game.Config.YamlConfigTextValidator.ValidateAsync(
            Metadata.TableName,
            GetSchemaPath(configRootPath),
            yamlPath,
            yamlText,
            cancellationToken);
    }

    /// <summary>
    ///     Exposes generated metadata for schema properties that declare <c>x-gframework-ref-table</c>.
    /// </summary>
    public static class References
    {
        /// <summary>
        ///     Gets generated reference metadata for schema property path 'dropItems'.
        /// </summary>
        public static readonly ReferenceMetadata DropItems = new(
            "dropItems",
            "item",
            "string",
            true);

        /// <summary>
        ///     Gets generated reference metadata for schema property path 'phases[].monsterId'.
        /// </summary>
        public static readonly ReferenceMetadata PhasesItemsMonsterId = new(
            "phases[].monsterId",
            "monster",
            "string",
            false);

        /// <summary>
        ///     Gets all generated cross-table reference descriptors for the current schema.
        /// </summary>
        public static global::System.Collections.Generic.IReadOnlyList<ReferenceMetadata> All { get; } = global::System.Array.AsReadOnly(new ReferenceMetadata[]
        {
            DropItems,
            PhasesItemsMonsterId,
        });

        /// <summary>
        ///     Tries to resolve generated reference metadata by schema property path.
        /// </summary>
        /// <param name="displayPath">Schema property path.</param>
        /// <param name="metadata">Resolved generated reference metadata when the path is known; otherwise the default value.</param>
        /// <returns>True when the schema property path has generated cross-table metadata; otherwise false.</returns>
        public static bool TryGetByDisplayPath(string displayPath, out ReferenceMetadata metadata)
        {
            if (displayPath is null)
            {
                throw new global::System.ArgumentNullException(nameof(displayPath));
            }

            if (string.Equals(displayPath, "dropItems", global::System.StringComparison.Ordinal))
            {
                metadata = DropItems;
                return true;
            }
            if (string.Equals(displayPath, "phases[].monsterId", global::System.StringComparison.Ordinal))
            {
                metadata = PhasesItemsMonsterId;
                return true;
            }

            metadata = default;
            return false;
        }
    }

    /// <summary>
    ///     Registers the generated config table using the schema-derived runtime conventions.
    /// </summary>
    /// <param name="loader">The target YAML config loader.</param>
    /// <param name="comparer">Optional key comparer for the generated table registration.</param>
    /// <returns>The same loader instance so registration can keep chaining.</returns>
    public static global::GFramework.Game.Config.YamlConfigLoader RegisterMonsterTable(
        this global::GFramework.Game.Config.YamlConfigLoader loader,
        global::System.Collections.Generic.IEqualityComparer<int>? comparer = null)
    {
        if (loader is null)
        {
            throw new global::System.ArgumentNullException(nameof(loader));
        }

        return loader.RegisterTable<int, MonsterConfig>(
            Metadata.TableName,
            Metadata.ConfigRelativePath,
            Metadata.SchemaRelativePath,
            static config => config.Id,
            comparer);
    }

    /// <summary>
    ///     Gets the generated config table wrapper from the registry.
    /// </summary>
    /// <param name="registry">The source config registry.</param>
    /// <returns>The generated strongly-typed table wrapper.</returns>
    /// <exception cref="global::System.ArgumentNullException">When <paramref name="registry"/> is null.</exception>
    public static MonsterTable GetMonsterTable(this global::GFramework.Game.Abstractions.Config.IConfigRegistry registry)
    {
        if (registry is null)
        {
            throw new global::System.ArgumentNullException(nameof(registry));
        }

        return new MonsterTable(registry.GetTable<int, MonsterConfig>(Metadata.TableName));
    }

    /// <summary>
    ///     Tries to get the generated config table wrapper from the registry.
    /// </summary>
    /// <param name="registry">The source config registry.</param>
    /// <param name="table">The generated strongly-typed table wrapper when lookup succeeds; otherwise null.</param>
    /// <returns>True when the generated table is registered and type-compatible; otherwise false.</returns>
    /// <exception cref="global::System.ArgumentNullException">When <paramref name="registry"/> is null.</exception>
    public static bool TryGetMonsterTable(this global::GFramework.Game.Abstractions.Config.IConfigRegistry registry, out MonsterTable? table)
    {
        if (registry is null)
        {
            throw new global::System.ArgumentNullException(nameof(registry));
        }

        if (registry.TryGetTable<int, MonsterConfig>(Metadata.TableName, out var innerTable) && innerTable is not null)
        {
            table = new MonsterTable(innerTable);
            return true;
        }

        table = null;
        return false;
    }
}
