import AppKit
import CryptoKit
import Foundation
import Observation

@Observable
@MainActor
final class StationArtworkLoader {
    private let cacheDirectory: URL
    private var memoryCache: [String: NSImage] = [:]
    private var inFlight: Set<String> = []

    init(cacheDirectory: URL) {
        self.cacheDirectory = cacheDirectory.appendingPathComponent("station_artwork")
    }

    func image(for station: RadioStation?) -> NSImage? {
        guard let urlString = normalizedArtworkURLString(for: station) else {
            return BearWaveAssets.image(named: "bearwave")
        }
        if let cached = memoryCache[urlString] {
            return cached
        }
        if let diskImage = NSImage(contentsOf: cacheURL(for: urlString)) {
            memoryCache[urlString] = diskImage
            return diskImage
        }
        load(urlString)
        return BearWaveAssets.image(named: "bearwave")
    }

    private func load(_ urlString: String) {
        guard !inFlight.contains(urlString), let url = URL(string: urlString) else { return }
        inFlight.insert(urlString)

        Task {
            defer {
                Task { @MainActor in self.inFlight.remove(urlString) }
            }
            do {
                var request = URLRequest(url: url)
                request.timeoutInterval = 10
                request.setValue("BearWave-macOS/1.0", forHTTPHeaderField: "User-Agent")
                let (data, response) = try await URLSession.shared.data(for: request)
                guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode),
                      let image = NSImage(data: data) else { return }

                try? FileManager.default.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
                try? data.write(to: cacheURL(for: urlString), options: .atomic)

                await MainActor.run {
                    memoryCache[urlString] = image
                }
            } catch {
                return
            }
        }
    }

    private func normalizedArtworkURLString(for station: RadioStation?) -> String? {
        guard let station else { return nil }
        let raw = station.favicon.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !raw.isEmpty else { return nil }
        if raw.hasPrefix("//") {
            return "https:\(raw)"
        }
        if raw.hasPrefix("http://") || raw.hasPrefix("https://") {
            return raw
        }
        return nil
    }

    private func cacheURL(for urlString: String) -> URL {
        let digest = SHA256.hash(data: Data(urlString.utf8))
        let hash = digest.map { String(format: "%02x", $0) }.joined()
        return cacheDirectory.appendingPathComponent("\(hash).image")
    }
}
