import Foundation
import Observation

@Observable
@MainActor
final class ProgressSyncManager {
    private let client: ABSClient
    private(set) var queuedCount: Int = 0
    private(set) var lastSyncError: String?

    /// Latest progress per itemId, persisted to disk.
    private var queue: [String: PlaybackProgress] = [:]

    private let queueFile: URL

    init(client: ABSClient) {
        self.client = client
        let dir = AppPaths.supportDirectory
        try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
        self.queueFile = dir.appendingPathComponent("progress-queue.json")
        loadQueue()
    }

    func report(itemId: String, episodeId: String? = nil, currentTime: Double, duration: Double, isFinished: Bool, isOnline: Bool) async {
        let progress = PlaybackProgress(
            itemId: itemId,
            episodeId: episodeId,
            currentTime: currentTime,
            duration: duration,
            isFinished: isFinished,
            updatedAt: Date()
        )
        let key = progress.syncKey

        if isOnline {
            do {
                try await client.saveProgress(progress)
                queue.removeValue(forKey: key)
                persist()
                lastSyncError = nil
                return
            } catch {
                lastSyncError = error.localizedDescription
            }
        }

        queue[key] = progress
        persist()
    }

    func drain() async {
        guard !queue.isEmpty else { return }
        let snapshot = queue
        for (id, progress) in snapshot {
            do {
                try await client.saveProgress(progress)
                queue.removeValue(forKey: id)
            } catch {
                lastSyncError = error.localizedDescription
                break
            }
        }
        persist()
    }

    private func loadQueue() {
        guard let data = try? Data(contentsOf: queueFile),
              let decoded = try? JSONDecoder().decode([String: PlaybackProgress].self, from: data) else { return }
        queue = decoded
        queuedCount = decoded.count
    }

    private func persist() {
        queuedCount = queue.count
        do {
            let data = try JSONEncoder().encode(queue)
            try data.write(to: queueFile, options: .atomic)
        } catch {
            lastSyncError = "Queue konnte nicht gespeichert werden: \(error.localizedDescription)"
        }
    }
}

enum AppPaths {
    nonisolated static var supportDirectory: URL {
        let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
            ?? URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Library/Application Support")
        return base.appendingPathComponent("AudiobookshelfClient", isDirectory: true)
    }

    nonisolated static var downloadsDirectory: URL {
        supportDirectory.appendingPathComponent("downloads", isDirectory: true)
    }
}
