using System.Text.Json;
using System.Text.Json.Serialization;
using YandexMusic.API.Models.Feed.Event;

namespace YandexMusic.API.Models.Feed;

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

        var events = new List<YFeedEventTitled>();
        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;

            // Определяем тип события: может быть в поле "typeForFrom" или "type"
            var typeToken = root.TryGetProperty("typeForFrom", out var tf) ? tf :
                           (root.TryGetProperty("type", out var t) ? t : throw new JsonException("Не найден тип события"));
            var typeStr = typeToken.GetString();
            if (!Enum.TryParse<YFeedEventType>(typeStr, true, out var eventType))
                throw new JsonException($"Неизвестный тип события: {typeStr}");

            YFeedEventTitled? feedEvent = null;
            var rawText = root.GetRawText();

            switch (eventType)
            {
                case YFeedEventType.GenreTop:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventGenreTracksTop>(rawText, options);
                    break;
                case YFeedEventType.NewAlbums:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventAlbums>(rawText, options);
                    break;
                case YFeedEventType.NewAlbumsOfFavoriteGenre:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventGenreAlbums>(rawText, options);
                    break;
                case YFeedEventType.Notification:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventNotification>(rawText, options);
                    break;
                case YFeedEventType.Promotion:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventPromotion>(rawText, options);
                    break;
                case YFeedEventType.RecentTrackLikeToTracks:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventLikeTrack>(rawText, options);
                    break;
                case YFeedEventType.RecommendedArtistsWithArtistsFromHistory:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventArtistWithArtists>(rawText, options);
                    break;
                case YFeedEventType.RecommendedSimilarArtists:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventSimilarArtists>(rawText, options);
                    break;
                case YFeedEventType.RecommendedSimilarGenre:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventSimilarGenre>(rawText, options);
                    break;
                case YFeedEventType.MissedTracksByArtist:
                case YFeedEventType.RareArtist:
                case YFeedEventType.RecommendedTracksByArtistFromHistory:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventArtist>(rawText, options);
                    break;
                case YFeedEventType.NewTracksOfFavoriteGenre:
                case YFeedEventType.TracksByGenre:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventGenreTracks>(rawText, options);
                    break;
                case YFeedEventType.WellForgottenOldArtists:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventArtists>(rawText, options);
                    break;
                case YFeedEventType.NeverHeardFromLibrary:
                case YFeedEventType.WellForgottenOldTracks:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventTracks>(rawText, options);
                    break;
                default:
                    feedEvent = JsonSerializer.Deserialize<YFeedEventTitled>(rawText, options);
                    break;
            }

            if (feedEvent != null)
                events.Add(feedEvent);
        }
        return events;
    }

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