using System.IO;
using System.Text.Json;
using NexusShell.Models;

namespace NexusShell.Services;

public sealed class NexusPlaylistService
{
    private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };

    private readonly string _playlistsFolder;
    private List<NexusMediaPlaylist> _playlists = [];

    public NexusPlaylistService()
    {
        _playlistsFolder = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "NinjaNexus",
            "media",
            "playlists");
        Directory.CreateDirectory(_playlistsFolder);
        LoadAll();
    }

    public string PlaylistsFolder => _playlistsFolder;

    public event EventHandler? PlaylistsChanged;

    public IReadOnlyList<NexusMediaPlaylist> GetPlaylists() => _playlists.ToList();

    public NexusMediaPlaylist? GetPlaylist(string id) =>
        _playlists.FirstOrDefault(p => string.Equals(p.Id, id, StringComparison.OrdinalIgnoreCase));

    public NexusMediaPlaylist CreatePlaylist(string name)
    {
        var playlist = new NexusMediaPlaylist
        {
            Id = Guid.NewGuid().ToString("N"),
            Name = string.IsNullOrWhiteSpace(name) ? "Ny afspilningsliste" : name.Trim(),
            CreatedUtc = DateTime.UtcNow,
            ItemPaths = [],
        };

        _playlists.Add(playlist);
        SavePlaylist(playlist);
        PlaylistsChanged?.Invoke(this, EventArgs.Empty);
        return playlist;
    }

    public void RenamePlaylist(string id, string name)
    {
        var playlist = GetPlaylist(id);
        if (playlist is null || string.IsNullOrWhiteSpace(name))
        {
            return;
        }

        var updated = new NexusMediaPlaylist
        {
            Id = playlist.Id,
            Name = name.Trim(),
            CreatedUtc = playlist.CreatedUtc,
            ItemPaths = playlist.ItemPaths,
        };

        ReplacePlaylist(updated);
    }

    public void DeletePlaylist(string id)
    {
        var playlist = GetPlaylist(id);
        if (playlist is null)
        {
            return;
        }

        _playlists.RemoveAll(p => string.Equals(p.Id, id, StringComparison.OrdinalIgnoreCase));
        var path = GetPlaylistFilePath(id);
        if (File.Exists(path))
        {
            File.Delete(path);
        }

        PlaylistsChanged?.Invoke(this, EventArgs.Empty);
    }

    public void AddToPlaylist(string playlistId, string mediaPath)
    {
        var playlist = GetPlaylist(playlistId);
        if (playlist is null || string.IsNullOrWhiteSpace(mediaPath))
        {
            return;
        }

        if (playlist.ItemPaths.Any(p => string.Equals(p, mediaPath, StringComparison.OrdinalIgnoreCase)))
        {
            return;
        }

        playlist.ItemPaths.Add(mediaPath);
        SavePlaylist(playlist);
        PlaylistsChanged?.Invoke(this, EventArgs.Empty);
    }

    public void RemoveFromPlaylist(string playlistId, string mediaPath)
    {
        var playlist = GetPlaylist(playlistId);
        if (playlist is null)
        {
            return;
        }

        playlist.ItemPaths.RemoveAll(p => string.Equals(p, mediaPath, StringComparison.OrdinalIgnoreCase));
        SavePlaylist(playlist);
        PlaylistsChanged?.Invoke(this, EventArgs.Empty);
    }

    public IReadOnlyList<NexusMediaItem> ResolvePlaylistItems(
        NexusMediaPlaylist playlist,
        IReadOnlyList<NexusMediaItem> library)
    {
        return playlist.ItemPaths
            .Select(path => library.FirstOrDefault(i =>
                string.Equals(i.FullPath, path, StringComparison.OrdinalIgnoreCase)))
            .Where(static i => i is not null)
            .Cast<NexusMediaItem>()
            .ToList();
    }

    private void LoadAll()
    {
        _playlists = [];
        if (!Directory.Exists(_playlistsFolder))
        {
            return;
        }

        foreach (var file in Directory.EnumerateFiles(_playlistsFolder, "*.json"))
        {
            try
            {
                var json = File.ReadAllText(file);
                var playlist = JsonSerializer.Deserialize<NexusMediaPlaylist>(json, JsonOptions);
                if (playlist is not null && !string.IsNullOrWhiteSpace(playlist.Id))
                {
                    _playlists.Add(playlist);
                }
            }
            catch
            {
                // Skip corrupt playlist files.
            }
        }

        _playlists = _playlists.OrderByDescending(static p => p.CreatedUtc).ToList();
    }

    private void ReplacePlaylist(NexusMediaPlaylist playlist)
    {
        _playlists.RemoveAll(p => string.Equals(p.Id, playlist.Id, StringComparison.OrdinalIgnoreCase));
        _playlists.Add(playlist);
        _playlists = _playlists.OrderByDescending(static p => p.CreatedUtc).ToList();
        SavePlaylist(playlist);
        PlaylistsChanged?.Invoke(this, EventArgs.Empty);
    }

    private void SavePlaylist(NexusMediaPlaylist playlist)
    {
        var json = JsonSerializer.Serialize(playlist, JsonOptions);
        File.WriteAllText(GetPlaylistFilePath(playlist.Id), json);
    }

    private string GetPlaylistFilePath(string id) => Path.Combine(_playlistsFolder, $"{id}.json");
}
