using DiscordRPC;
using System;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

class Program
{
    private const string ConfigFilePath = "config.json";
    private static DiscordRpcClient _discordClient;
    private static Config _config;

    // Hard-coded the Discord Client ID
    private const string DiscordClientId = "1312264302601834578";

    static bool presenceUpdated = false; // Flag to track initial rich presence update

    static async Task Main(string[] args)
    {
        // Load or create configuration first
        LoadOrCreateConfig();  // Initialize _config first

        // Now we can safely access _config for the console title
        Console.WriteLine("Starting Jellyfin Discord Rich Presence...");
        Console.Title = $"Jellyfin Discord RPC - {_config.JellyfinBaseUrl}";

        // Initialize Discord Rich Presence
        _discordClient = new DiscordRpcClient(DiscordClientId);
        _discordClient.OnReady += (sender, e) =>
        {
            Console.WriteLine("Connected to Discord RPC!");

            // Log message when connection to Discord is established
            if (!presenceUpdated)
            {
                Console.WriteLine("Rich Presence updated!"); // This will only show once
                presenceUpdated = true; // Set the flag to true to avoid logging it again
            }
        };

        // Handle presence updates only once at the start
        _discordClient.OnPresenceUpdate += (sender, e) =>
        {
            if (!presenceUpdated)
            {
                Console.WriteLine("Rich Presence updated!");
                presenceUpdated = true;  // Set the flag to true so it doesn't display again
            }
        };

        _discordClient.Initialize();

        // Poll Jellyfin API for currently playing media
        var updateTask = UpdateRichPresence();  // Start the rich presence update task

        await updateTask;  // Wait for the rich presence update task to finish
    }

    private static async Task UpdateRichPresence()
    {
        while (true)
        {
            try
            {
                var playingInfo = await GetCurrentlyPlaying().ConfigureAwait(false);
                if (playingInfo != null)
                {
                    JToken nowPlaying = playingInfo.NowPlayingItem;

                    string largeImageKey = playingInfo.IsMusic
                        ? await GetAlbumCover(nowPlaying).ConfigureAwait(false)
                        : await GetJellyfinLogo().ConfigureAwait(false);
                    string largeImageText = playingInfo.IsMusic
                        ? nowPlaying["Album"]?.ToString() ?? "Unknown Album"
                        : "Jellyfin Media Player";

                    string details = playingInfo.IsMusic
                        ? $"{playingInfo.Title}" // Show song name
                        : nowPlaying["SeriesName"] != null
                            ? $"Watching: {nowPlaying["SeriesName"]} - {playingInfo.Title}" // Show series and episode name
                            : $"Watching: {playingInfo.Title}"; // For movies, show only the title

                    string state = playingInfo.IsMusic
                        ? $"{playingInfo.Artist}"  // Show artist name
                        : nowPlaying["SeriesName"] != null
                            ? $"Season {playingInfo.Season}, Episode {playingInfo.Episode}" // Show season and episode for series
                            : ""; // Leave state empty for movies

                    Console.WriteLine($"Updating presence with details: {details}, state: {state}");

                    _discordClient.SetPresence(new RichPresence
                    {
                        Details = details,
                        State = string.IsNullOrWhiteSpace(state) ? null : state, // Avoid sending empty state to Discord
                        Timestamps = new Timestamps
                        {
                            Start = DateTime.UtcNow - playingInfo.Progress,
                            End = DateTime.UtcNow + (playingInfo.Duration - playingInfo.Progress)
                        },
                        Assets = new Assets
                        {
                            LargeImageKey = largeImageKey,
                            LargeImageText = largeImageText
                        }
                    });
                }
                else
                {
                    _discordClient.ClearPresence();
                    Console.WriteLine("No media playing, clearing presence.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error fetching Jellyfin data: {ex.Message}");
            }

            // Wait before polling again
            await Task.Delay(5000).ConfigureAwait(false);
        }
    }

    private static async Task<string> GetJellyfinLogo()
    {
        using var httpClient = new HttpClient();
        try
        {
            var response = await httpClient.GetAsync($"{_config.JellyfinBaseUrl}/System/Info?api_key={_config.JellyfinApiKey}").ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            var json = JObject.Parse(jsonResponse);

            var logoUrl = json["LogoUrl"]?.ToString();
            return logoUrl ?? "jellyfin_logo";
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error fetching Jellyfin logo: {ex.Message}");
            return "jellyfin_logo"; // Default fallback
        }
    }

    private static void LoadOrCreateConfig()
    {
        if (File.Exists(ConfigFilePath))
        {
            var configJson = File.ReadAllText(ConfigFilePath);
            _config = JsonSerializer.Deserialize<Config>(configJson);
        }
        else
        {
            _config = new Config();
            Console.Write("Enter Jellyfin Server URL: ");
            _config.JellyfinBaseUrl = Console.ReadLine();
            Console.Write("Enter Jellyfin API Key: ");
            _config.JellyfinApiKey = Console.ReadLine();
            Console.Write("Enter Jellyfin User ID: ");
            _config.JellyfinUserId = Console.ReadLine();

            var configJson = JsonSerializer.Serialize(_config, new JsonSerializerOptions { WriteIndented = true });
            File.WriteAllText(ConfigFilePath, configJson);
            Console.WriteLine("Configuration saved to config.json.");
        }
    }

    private static async Task<PlayingInfo?> GetCurrentlyPlaying()
    {
        using var httpClient = new HttpClient();
        try
        {
            var response = await httpClient.GetAsync($"{_config.JellyfinBaseUrl}/Sessions?api_key={_config.JellyfinApiKey}").ConfigureAwait(false);
            response.EnsureSuccessStatusCode();

            var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            var sessions = JArray.Parse(jsonResponse);

            foreach (var session in sessions)
            {
                if (session["UserId"]?.ToString() == _config.JellyfinUserId && session["NowPlayingItem"] != null)
                {
                    var nowPlaying = session["NowPlayingItem"];
                    var mediaType = nowPlaying["Type"]?.ToString();
                    bool isMusic = mediaType?.ToLower() == "audio";

                    string albumCover = "";
                    string artist = "Unknown Artist";

                    if (isMusic)
                    {
                        albumCover = await GetAlbumCover(nowPlaying).ConfigureAwait(false);
                        var artists = nowPlaying["Artists"]?.ToObject<JArray>();
                        if (artists != null && artists.Count > 0)
                        {
                            artist = artists[0].ToString();
                        }
                    }
                    else
                    {
                        artist = "Unknown Artist";
                    }

                    return new PlayingInfo
                    {
                        Title = nowPlaying["Name"]?.ToString(),
                        Artist = artist,
                        AlbumCover = albumCover,
                        Season = nowPlaying["ParentIndexNumber"]?.ToString() ?? "N/A",
                        Episode = nowPlaying["IndexNumber"]?.ToString() ?? "N/A",
                        Progress = TimeSpan.FromTicks((long)session["PlayState"]["PositionTicks"]),
                        Duration = TimeSpan.FromTicks((long)nowPlaying["RunTimeTicks"]),
                        IsMusic = isMusic,
                        NowPlayingItem = nowPlaying,
                        EndDate = DateTime.UtcNow + TimeSpan.FromTicks((long)nowPlaying["RunTimeTicks"]) // Calculating end date based on duration
                    };
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error fetching Jellyfin data: {ex.Message}");
        }

        return null;
    }

    private static async Task<string> GetAlbumCover(JToken nowPlaying)
    {
        var mediaStreams = nowPlaying["MediaStreams"]?.ToObject<JArray>();
        if (mediaStreams != null)
        {
            foreach (var stream in mediaStreams)
            {
                var imageTag = stream["ImageTag"]?.ToString();
                if (!string.IsNullOrEmpty(imageTag))
                {
                    return imageTag;  // Return the album cover image tag
                }
            }
        }
        return "album_cover";
    }
}

class Config
{
    public string JellyfinBaseUrl { get; set; }
    public string JellyfinApiKey { get; set; }
    public string JellyfinUserId { get; set; }
}

class PlayingInfo
{
    public string Title { get; set; }
    public string Artist { get; set; }
    public string AlbumCover { get; set; }
    public string Season { get; set; }
    public string Episode { get; set; }
    public TimeSpan Progress { get; set; }
    public TimeSpan Duration { get; set; }
    public bool IsMusic { get; set; }
    public JToken NowPlayingItem { get; set; }
    public DateTime EndDate { get; set; }
}