using System.Text.RegularExpressions;

namespace TakeoutSaaS.Domain.Dictionary.ValueObjects;

/// <summary>
/// 字典分组编码值对象。
/// </summary>
public readonly struct DictionaryCode : IEquatable<DictionaryCode>
{
    private static readonly Regex CodePattern = new("^[a-zA-Z0-9_]{2,64}$", RegexOptions.Compiled);
    private readonly string? _value;

    /// <summary>
    /// 初始化字典编码并进行规范化。
    /// </summary>
    /// <param name="value">原始编码。</param>
    /// <exception cref="ArgumentException">编码非法时抛出。</exception>
    public DictionaryCode(string value)
    {
        _value = Normalize(value);
    }

    /// <summary>
    /// 规范化后的编码值。
    /// </summary>
    public string Value => _value ?? string.Empty;

    /// <summary>
    /// 判断编码是否符合规则。
    /// </summary>
    public static bool IsValid(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        var trimmed = value.Trim();
        return CodePattern.IsMatch(trimmed);
    }

    /// <summary>
    /// 规范化编码（去空格、转小写并校验）。
    /// </summary>
    /// <param name="value">原始编码。</param>
    /// <returns>规范化后的编码。</returns>
    /// <exception cref="ArgumentException">编码非法时抛出。</exception>
    public static string Normalize(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException("Dictionary code is required.", nameof(value));
        }

        var trimmed = value.Trim();
        if (!CodePattern.IsMatch(trimmed))
        {
            throw new ArgumentException("Dictionary code must be 2-64 characters of letters, digits, or underscore.", nameof(value));
        }

        return trimmed.ToLowerInvariant();
    }

    /// <inheritdoc />
    public bool Equals(DictionaryCode other)
        => StringComparer.Ordinal.Equals(Value, other.Value);

    /// <inheritdoc />
    public override bool Equals(object? obj)
        => obj is DictionaryCode other && Equals(other);

    /// <inheritdoc />
    public override int GetHashCode()
        => StringComparer.Ordinal.GetHashCode(Value);

    /// <inheritdoc />
    public override string ToString()
        => Value;

    public static bool operator ==(DictionaryCode left, DictionaryCode right)
        => left.Equals(right);

    public static bool operator !=(DictionaryCode left, DictionaryCode right)
        => !left.Equals(right);

    public static implicit operator string(DictionaryCode code)
        => code.Value;

    public static implicit operator DictionaryCode(string value)
        => new(value);
}
