import Foundation

actor PlaylistService {
    nonisolated(unsafe) static let shared = PlaylistService()

    private let networkService = NetworkService.shared
    private let parser = M3UParser()
    private var cachedPlaylist: Playlist?

    private let cacheFileName = "playlist_cache.json"
    private let cacheTTL: TimeInterval = 12 * 60 * 60  // 12 hours

    private var cacheFileURL: URL {
        FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
            .appendingPathComponent(cacheFileName)
    }

    private init() {}

    func fetchVODPlaylist(credentials: XStreamCredentials, forceRefresh: Bool = false) async throws -> Playlist {
        // Check memory cache first
        if !forceRefresh, let cached = cachedPlaylist {
            return cached
        }

        // Check disk cache if memory cache is empty
        if !forceRefresh, let diskCached = loadFromCache() {
            cachedPlaylist = diskCached
            return diskCached
        }

        guard let playlistURL = credentials.constructPlaylistURL() else {
            throw NetworkError.invalidURL
        }

        do {
            let m3uString = try await networkService.downloadString(from: playlistURL)

            let vodItems = try parser.parse(data: m3uString)

            let categories = parser.extractCategories(from: vodItems)

            let playlist = Playlist(
                vodItems: vodItems,
                categories: categories,
                lastUpdated: Date()
            )

            // Update memory cache
            cachedPlaylist = playlist

            // Save to disk cache
            saveToCache(playlist)

            return playlist

        } catch let error as M3UParserError {
            throw NetworkError.playlistParsingFailed(error.localizedDescription)
        } catch let error as NetworkError {
            throw error
        } catch {
            throw NetworkError.unknown(error)
        }
    }

    func clearCache() {
        cachedPlaylist = nil
        deleteCacheFile()
    }

    func getCachedPlaylist() -> Playlist? {
        if let cached = cachedPlaylist {
            return cached
        }
        if let diskCached = loadFromCache() {
            cachedPlaylist = diskCached
            return diskCached
        }
        return nil
    }

    func isCacheStale(_ playlist: Playlist) -> Bool {
        let age = Date().timeIntervalSince(playlist.lastUpdated)
        return age > cacheTTL
    }

    // MARK: - Private Disk Cache Methods

    private func saveToCache(_ playlist: Playlist) {
        do {
            let encoder = JSONEncoder()
            let data = try encoder.encode(playlist)
            try data.write(to: cacheFileURL, options: .atomic)
        } catch {
            // Silent failure - disk cache is non-critical
        }
    }

    private func loadFromCache() -> Playlist? {
        do {
            let data = try Data(contentsOf: cacheFileURL)
            let decoder = JSONDecoder()
            return try decoder.decode(Playlist.self, from: data)
        } catch {
            return nil
        }
    }

    private func deleteCacheFile() {
        try? FileManager.default.removeItem(at: cacheFileURL)
    }
}
