import AVFoundation
import Combine
import Foundation

@MainActor
final class PlayerCoordinator: ObservableObject {
    let player: AVPlayer

    @Published var isPlaying = false
    @Published var playbackPositionMs: Int = 0
    @Published var playbackCompletionCount = 0

    private var playbackEndObserver: NSObjectProtocol?

    init() {
        self.player = AVPlayer()
        self.player.actionAtItemEnd = .pause
    }

    deinit {
        if let playbackEndObserver {
            NotificationCenter.default.removeObserver(playbackEndObserver)
        }
    }

    func prepareForPreview(url: URL, startTimeMs: Int = 0) {
        player.replaceCurrentItem(with: AVPlayerItem(url: url))
        observePlaybackEnd(for: player.currentItem)
        let startTime = CMTime(seconds: Double(startTimeMs) / 1_000.0, preferredTimescale: 1_000)
        player.seek(to: startTime)
        player.play()
        isPlaying = true
    }

    func play() {
        player.play()
        isPlaying = true
    }

    func play(rate: Float) {
        player.playImmediately(atRate: rate)
        isPlaying = true
    }

    func pause() {
        player.pause()
        isPlaying = false
    }

    func seek(to timeMs: Int) {
        let time = CMTime(seconds: Double(timeMs) / 1_000.0, preferredTimescale: 1_000)
        player.seek(to: time)
    }

    func play(url: URL, startTimeMs: Int, rate: Float) {
        prepareForPreview(url: url, startTimeMs: startTimeMs)
        play(rate: rate)
    }

    func restart(url: URL, startTimeMs: Int = 0) {
        prepareForPreview(url: url, startTimeMs: startTimeMs)
    }

    private func observePlaybackEnd(for item: AVPlayerItem?) {
        if let playbackEndObserver {
            NotificationCenter.default.removeObserver(playbackEndObserver)
            self.playbackEndObserver = nil
        }

        guard let item else {
            return
        }

        playbackEndObserver = NotificationCenter.default.addObserver(
            forName: .AVPlayerItemDidPlayToEndTime,
            object: item,
            queue: .main
        ) { [weak self] _ in
            Task { @MainActor [weak self] in
                self?.isPlaying = false
                self?.playbackCompletionCount += 1
            }
        }
    }
}
