namespace RioJoy.Core.Profiles;

/// <summary>
/// Minimal INI reader (sections, <c>key = value</c>, <c>;</c>/<c>#</c> comments)
/// sufficient to parse the legacy <c>RIO.ini</c>. Keys are case-insensitive.
/// </summary>
public sealed class IniFile
{
    private readonly Dictionary<string, Dictionary<string, string>> _sections =
        new(StringComparer.OrdinalIgnoreCase);

    public static IniFile Parse(string text)
    {
        if (text is null) throw new ArgumentNullException(nameof(text));
        var ini = new IniFile();
        var current = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        ini._sections[string.Empty] = current;

        foreach (string rawLine in text.Split('\n'))
        {
            string line = rawLine.Trim();
            if (line.Length == 0 || line[0] is ';' or '#')
                continue;

            if (line[0] == '[' && line[^1] == ']')
            {
                string section = line[1..^1].Trim();
                if (!ini._sections.TryGetValue(section, out current!))
                    ini._sections[section] = current = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                continue;
            }

            int eq = line.IndexOf('=');
            if (eq < 0)
                continue;

            string key = line[..eq].Trim();
            string value = line[(eq + 1)..].Trim();
            if (key.Length > 0)
                current[key] = value;
        }

        return ini;
    }

    /// <summary>All key/value pairs in a section (empty if the section is absent).</summary>
    public IDictionary<string, string> Section(string name) =>
        _sections.TryGetValue(name, out Dictionary<string, string>? s)
            ? s
            : new Dictionary<string, string>();

    public string? GetString(string section, string key) =>
        Section(section).TryGetValue(key, out string? v) ? v : null;

    public bool GetBool(string section, string key, bool fallback)
    {
        string? v = GetString(section, key);
        if (v is null)
            return fallback;
        return v.Trim().ToLowerInvariant() switch
        {
            "1" or "true" or "yes" or "on" => true,
            "0" or "false" or "no" or "off" => false,
            _ => fallback,
        };
    }

    /// <summary>Parse an integer value that may be hex (<c>0x…</c>) or decimal.</summary>
    public static int ParseInt(string value)
    {
        if (value is null) throw new ArgumentNullException(nameof(value));
        string v = value.Trim();
        bool neg = v.StartsWith("-", StringComparison.Ordinal);
        if (neg) v = v[1..];

        int magnitude = v.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
            ? Convert.ToInt32(v[2..], 16)
            : int.Parse(v);

        return neg ? -magnitude : magnitude;
    }
}
