using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using YamlDotNet.Serialization;
using PCL.Core.Utils;

namespace PCL.Core.App.Configuration.Storage;

// Partly generated by gpt-5-mini (20250903)
public static class JsonToYamlConverter
{
    /// <summary>
    /// 从 jsonInput 读取 JSON，转换为 YAML 写入 yamlOutput。
    /// </summary>
    /// <param name="jsonInput">可读的 JSON 输入流</param>
    /// <param name="yamlOutput">可写的 YAML 输出流</param>
    /// <param name="leaveOpen">是否在返回时保留输出流打开</param>
    public static void Convert(Stream jsonInput, Stream yamlOutput, bool leaveOpen = false)
    {
        ArgumentNullException.ThrowIfNull(jsonInput);
        ArgumentNullException.ThrowIfNull(yamlOutput);
        if (!jsonInput.CanRead) throw new ArgumentException("must be readable", nameof(jsonInput));
        if (!yamlOutput.CanWrite) throw new ArgumentException("must be writable", nameof(yamlOutput));

        using var doc = JsonDocument.Parse(jsonInput, JsonCompat.DocumentOptions);
        var obj = _ConvertElement(doc.RootElement);

        var serializer = new SerializerBuilder().Build();
        using var writer = new StreamWriter(yamlOutput, new UTF8Encoding(false), 8192, leaveOpen);
        serializer.Serialize(writer, obj);
        writer.Flush();
    }

    /// <summary>
    /// 异步从 jsonInput 读取 JSON，转换为 YAML 写入 yamlOutput。
    /// </summary>
    /// <param name="jsonInput">可读的 JSON 输入流</param>
    /// <param name="yamlOutput">可写的 YAML 输出流</param>
    /// <param name="leaveOpen">是否在返回时保留输出流打开</param>
    public static async Task ConvertAsync(Stream jsonInput, Stream yamlOutput, bool leaveOpen = false)
    {
        ArgumentNullException.ThrowIfNull(jsonInput);
        ArgumentNullException.ThrowIfNull(yamlOutput);
        if (!jsonInput.CanRead) throw new ArgumentException("jsonInput must be readable", nameof(jsonInput));
        if (!yamlOutput.CanWrite) throw new ArgumentException("yamlOutput must be writable", nameof(yamlOutput));

        using var doc = await JsonDocument.ParseAsync(jsonInput, JsonCompat.DocumentOptions).ConfigureAwait(false);
        var obj = _ConvertElement(doc.RootElement);

        var serializer = new SerializerBuilder().Build();
        await using var streamWriter = new StreamWriter(yamlOutput, new UTF8Encoding(false), 8192, leaveOpen);
        serializer.Serialize(streamWriter, obj);
        await streamWriter.FlushAsync().ConfigureAwait(false);
    }

    private static object? _ConvertElement(JsonElement element)
    {
        switch (element.ValueKind)
        {
            case JsonValueKind.Object:
            {
                var dict = new Dictionary<string, object?>(StringComparer.Ordinal);
                foreach (var prop in element.EnumerateObject())
                {
                    dict[prop.Name] = _ConvertElement(prop.Value);
                }
                return dict;
            }

            case JsonValueKind.Array:
            {
                return element.EnumerateArray().Select(_ConvertElement).ToList();
            }

            case JsonValueKind.String: return element.GetString();

            case JsonValueKind.Number:
            {
                // 尽量保留数值类型：先尝试 Int64，再尝试 decimal（避免浮点精度丢失），最后尝试 double
                if (element.TryGetInt64(out var l)) return l;

                var raw = element.GetRawText();
                if (decimal.TryParse(raw, NumberStyles.Any, CultureInfo.InvariantCulture, out var dec)) return dec;

                if (element.TryGetDouble(out var d)) return d;

                // 兜底：返回原始文本
                return raw;
            }

            case JsonValueKind.True: return true;
            case JsonValueKind.False: return false;

            case JsonValueKind.Null:
            case JsonValueKind.Undefined:
            default:
                return null;
        }
    }
}
