using System.IO;
using NexusShell.Models;

namespace NexusShell.Services;

public sealed class NexusMediaMetadataService
{
    public NexusMediaMetadata BuildMetadata(NexusMediaItem? item)
    {
        if (item is null)
        {
            return EmptyMetadata();
        }

        return new NexusMediaMetadata
        {
            Title = item.Title,
            FileName = item.FileName,
            SizeLabel = NexusMediaFormatting.FormatBytes(item.FileSizeBytes),
            DurationLabel = item.DurationLabel,
            Format = item.Format,
            ResolutionLabel = item.Kind == NexusMediaKind.Video ? item.ResolutionLabel : "—",
            BitrateLabel = item.BitrateKbps is > 0 ? $"{item.BitrateKbps} kbps" : "—",
            CodecLabel = string.IsNullOrWhiteSpace(item.Codec) ? item.Format : item.Codec!,
            ArtistLabel = item.Artist,
            AlbumLabel = item.Album,
            FolderLabel = item.FolderLabel,
            FullPath = item.FullPath,
            HasSelection = true,
        };
    }

    public NexusMediaProbeResult ProbeFile(string filePath, NexusMediaKind kind)
    {
        var fileName = Path.GetFileNameWithoutExtension(filePath);
        var result = new NexusMediaProbeResult
        {
            Title = fileName,
            Artist = "Ukendt kunstner",
            Album = "Ukendt album",
        };

        if (kind == NexusMediaKind.Audio)
        {
            TryReadAudioTags(filePath, result);
        }

        return result;
    }

    public NexusMediaMetadata MergeRuntime(
        NexusMediaItem item,
        TimeSpan duration,
        int videoWidth,
        int videoHeight)
    {
        var merged = new NexusMediaItem
        {
            FullPath = item.FullPath,
            FileName = item.FileName,
            Title = item.Title,
            FolderPath = item.FolderPath,
            FolderLabel = item.FolderLabel,
            FileSizeBytes = item.FileSizeBytes,
            CreatedUtc = item.CreatedUtc,
            ModifiedUtc = item.ModifiedUtc,
            Format = item.Format,
            Extension = item.Extension,
            Kind = item.Kind,
            Artist = item.Artist,
            Album = item.Album,
            Duration = duration > TimeSpan.Zero ? duration : item.Duration,
            VideoWidth = videoWidth > 0 ? videoWidth : item.VideoWidth,
            VideoHeight = videoHeight > 0 ? videoHeight : item.VideoHeight,
            Codec = item.Codec,
            BitrateKbps = item.BitrateKbps ?? EstimateBitrateKbps(item.FileSizeBytes, duration),
            IsFavorite = item.IsFavorite,
        };

        return BuildMetadata(merged);
    }

    private static void TryReadAudioTags(string filePath, NexusMediaProbeResult result)
    {
        try
        {
            using var tagFile = TagLib.File.Create(filePath);
            if (!string.IsNullOrWhiteSpace(tagFile.Tag.Title))
            {
                result.Title = tagFile.Tag.Title;
            }

            if (!string.IsNullOrWhiteSpace(tagFile.Tag.FirstPerformer))
            {
                result.Artist = tagFile.Tag.FirstPerformer;
            }

            if (!string.IsNullOrWhiteSpace(tagFile.Tag.Album))
            {
                result.Album = tagFile.Tag.Album;
            }

            if (tagFile.Properties.Duration > TimeSpan.Zero)
            {
                result.Duration = tagFile.Properties.Duration;
            }

            if (tagFile.Properties.AudioBitrate > 0)
            {
                result.BitrateKbps = tagFile.Properties.AudioBitrate / 1000;
            }

            var codec = tagFile.Properties.Codecs.FirstOrDefault()?.Description;
            if (!string.IsNullOrWhiteSpace(codec))
            {
                result.Codec = codec;
            }
        }
        catch
        {
            // Tag read is best-effort for POC.
        }
    }

    private static int? EstimateBitrateKbps(long bytes, TimeSpan duration)
    {
        if (duration <= TimeSpan.Zero || bytes <= 0)
        {
            return null;
        }

        return (int)Math.Round(bytes * 8.0 / duration.TotalSeconds / 1000.0);
    }

    private static NexusMediaMetadata EmptyMetadata() => new()
    {
        Title = "—",
        FileName = "—",
        SizeLabel = "—",
        DurationLabel = "—",
        Format = "—",
        ResolutionLabel = "—",
        BitrateLabel = "—",
        CodecLabel = "—",
        ArtistLabel = "—",
        AlbumLabel = "—",
        FolderLabel = "—",
        FullPath = "—",
        HasSelection = false,
    };
}

public sealed class NexusMediaProbeResult
{
    public required string Title { get; set; }
    public required string Artist { get; set; }
    public required string Album { get; set; }
    public TimeSpan Duration { get; set; }
    public int VideoWidth { get; set; }
    public int VideoHeight { get; set; }
    public string? Codec { get; set; }
    public int? BitrateKbps { get; set; }
}
