import AVFoundation
import Foundation
import UIKit

/// Loads album artwork from folder images or embedded metadata.
actor ArtworkService {

    static let shared = ArtworkService()

    /// Cache keyed by track file path (not folder) so each track gets its own artwork.
    private var cache: [String: UIImage?] = [:]

    private static let coverFileNames: [String] = [
        "cover", "folder", "front", "album", "albumart",
        "albumartsmall", "thumb", "artwork", "art",
        "Cover", "Folder", "Front", "Album"
    ]

    private static let imageExtensions: Set<String> = [
        "jpg", "jpeg", "png", "bmp", "gif", "tiff", "webp"
    ]

    // MARK: - Public API

    /// Get artwork for a track. Pass the URL directly to avoid SwiftData model access issues.
    func artwork(for trackURL: URL) async -> UIImage? {
        let trackPath = trackURL.path

        // Check cache (nil value means we already tried and found nothing)
        if let cached = cache[trackPath] {
            return cached
        }

        // Only access files within the app sandbox
        let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        guard trackPath.hasPrefix(docsDir.path) else {
            cache[trackPath] = Optional<UIImage>.none
            return nil
        }

        // 1. Try embedded metadata FIRST (most accurate per-track)
        if FileManager.default.fileExists(atPath: trackPath),
           let embedded = await extractEmbeddedArtwork(from: trackURL) {
            cache[trackPath] = embedded
            return embedded
        }

        // 2. Try folder images (cover.jpg etc.)
        let folderURL = trackURL.deletingLastPathComponent()
        if let folderArt = findFolderArtwork(in: folderURL) {
            cache[trackPath] = folderArt
            return folderArt
        }

        // Cache nil so we don't retry
        cache[trackPath] = Optional<UIImage>.none
        return nil
    }

    func clearCache() {
        cache.removeAll()
    }

    // MARK: - Folder Artwork

    private func findFolderArtwork(in folderURL: URL) -> UIImage? {
        let fm = FileManager.default

        for name in Self.coverFileNames {
            for ext in Self.imageExtensions {
                let candidate = folderURL.appendingPathComponent("\(name).\(ext)")
                if fm.fileExists(atPath: candidate.path),
                   let data = try? Data(contentsOf: candidate),
                   let image = UIImage(data: data) {
                    return image
                }
            }
        }

        // Fallback: any image file in the folder
        if let contents = try? fm.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) {
            for fileURL in contents {
                if Self.imageExtensions.contains(fileURL.pathExtension.lowercased()),
                   let data = try? Data(contentsOf: fileURL),
                   let image = UIImage(data: data) {
                    return image
                }
            }
        }

        return nil
    }

    // MARK: - Embedded Artwork

    private func extractEmbeddedArtwork(from url: URL) async -> UIImage? {
        let asset = AVURLAsset(url: url)
        guard let metadata = try? await asset.load(.metadata) else { return nil }

        for item in metadata {
            guard item.commonKey == .commonKeyArtwork else { continue }
            if let data = try? await item.load(.dataValue),
               let image = UIImage(data: data) {
                return image
            }
        }

        return nil
    }
}
