using System.Text.Json;
using System.Text.Json.Serialization;
using YandexMusic.API.Models.Pins.Items;

namespace YandexMusic.API.Models.Pins;

/// <summary>Конвертер для закреплённых объектов (пинов). Десериализует в конкретные типы на основе поля type.</summary>
public class YPinConverter : JsonConverter<List<YPin>>
{
    public override List<YPin> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartArray)
            throw new JsonException("Ожидается массив пинов");

        var pins = new List<YPin>();
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndArray)
                break;

            if (reader.TokenType != JsonTokenType.StartObject)
                throw new JsonException("Ожидается объект пина");

            using var doc = JsonDocument.ParseValue(ref reader);
            var root = doc.RootElement;

            var typeProp = root.GetProperty("type");
            var typeStr = typeProp.GetString();
            if (!Enum.TryParse<YPinType>(typeStr, true, out var pinType))
                throw new JsonException($"Неизвестный тип пина: {typeStr}");

            YPin? pin = null;
            var rawText = root.GetRawText();

            switch (pinType)
            {
                case YPinType.Album:
                    pin = JsonSerializer.Deserialize<YPin<YPinAlbumData>>(rawText, options);
                    break;
                case YPinType.Artist:
                    pin = JsonSerializer.Deserialize<YPin<YPinArtistData>>(rawText, options);
                    break;
                case YPinType.Playlist:
                    pin = JsonSerializer.Deserialize<YPin<YPinPlaylistData>>(rawText, options);
                    break;
                case YPinType.Wave:
                    pin = JsonSerializer.Deserialize<YPin<YPinWaveData>>(rawText, options);
                    break;
                default:
                    pin = JsonSerializer.Deserialize<YPin>(rawText, options);
                    break;
            }

            if (pin != null)
                pins.Add(pin);
        }
        return pins;
    }

    public override void Write(Utf8JsonWriter writer, List<YPin> value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value, options);
    }
}