import Foundation
import AVFoundation
import PRESTOplay

public class PlayerEventEmitter: DrmEventEmitter {

    // MARK: Lifecycle

    public override init(_ parentModule: AnyObject) {
        super.init(parentModule)
    }

    // MARK: Internal

    func emitStateChanged(playerId: String, state: PlaybackState) {
        emit(
            consumerId: playerId,
            eventType: "stateChanged",
            eventDetails: [
                "currentState": BridgeSerializer.toPlayerState(state),
            ],
            preventDuplicates: true
        )
    }

    func emitPositionChanged(playerId: String, positionMs: Int64, liveStartTimeMs: Int64?) {
        var eventDetails: [String: Any] = [
            "position": positionMs
        ]

        if let liveStartTimeMs {
            eventDetails["liveStartTime"] = liveStartTimeMs
        }

        emit(
            consumerId: playerId,
            eventType: "positionChanged",
            eventDetails: eventDetails,
            preventDuplicates: true
        )
    }


    func emitPlayWhenReadyChanged(playerId: String, playWhenReady: Bool) {
        emit(
            consumerId: playerId,
            eventType: "playWhenReadyChanged",
            eventDetails: [
                "playWhenReady": playWhenReady,
            ]
        )
    }

    func emitPictureInPictureModeChanged(playerId: String, pictureInPictureMode: Bool) {
        emit(
            consumerId: playerId,
            eventType: "pictureInPictureModeChanged",
            eventDetails: [
                "pictureInPictureMode": pictureInPictureMode,
            ]
        )
    }

    func emitTrackModelChanged(
        playerId: String,
        videoTracks: [PRESTOplay.VideoTrack],
        audioTracks: [PRESTOplay.AudioTrack],
        textTracks: [PRESTOplay.TextTrack],
        currentVideoTrack: PRESTOplay.VideoTrack?,
        currentAudioTrack: PRESTOplay.AudioTrack?,
        currentTextTrack: PRESTOplay.TextTrack?,
        currentVideoRendition: PRESTOplay.VideoRendition?,
        isAdaptationModeManual: Bool
    ) {
        emit(
            consumerId: playerId,
            eventType: "trackModelChanged",
            eventDetails: [
                "adaptiveVideoEnabled": !isAdaptationModeManual,
                "videoTracks": BridgeSerializer.toVideoTracks(
                    tracks: videoTracks,
                    currentTrack: currentVideoTrack,
                    currentRendition: currentVideoRendition
                ),
                "audioTracks": BridgeSerializer.toAudioTracks(
                    tracks: audioTracks,
                    currentTrack: currentAudioTrack
                ),
                "textTracks": BridgeSerializer.toTextTracks(
                    tracks: textTracks,
                    currentTrack: currentTextTrack
                ),
            ],
            preventDuplicates: true
        )
    }
    
    func emitTrackModelChanged(
        playerId: String,
        videoTracks: [AVAssetTrack],
        audioTracks: AVMediaSelectionGroup?,
        textTracks: AVMediaSelectionGroup?,
        currentAudioTrack: AVMediaSelectionOption?,
        currentTextTrack: AVMediaSelectionOption?,
        isAdaptationModeManual: Bool
    ) async throws {
        emit(
            consumerId: playerId,
            eventType: "trackModelChanged",
            eventDetails: [
                "adaptiveVideoEnabled": !isAdaptationModeManual,
                "videoTracks": try await BridgeSerializer.toVideoTracks(
                    tracks: videoTracks
                ),
                "audioTracks": try await (audioTracks != nil ? BridgeSerializer.toAudioTracks(
                    tracks: audioTracks!,
                    currentTrack: currentAudioTrack)
                  : []),
                "textTracks": try await (textTracks != nil ? BridgeSerializer.toTextTracks(
                    tracks: textTracks!,
                    currentTrack: currentTextTrack)
                  : [])
            ],
            preventDuplicates: true
        )
    }

    func emitDurationChanged(
        playerId: String,
        durationMs: Int64
    ) {
        emit(
            consumerId: playerId,
            eventType: "durationChanged",
            eventDetails: [
                "duration": durationMs,
            ],
            preventDuplicates: true
        )
    }

    func emitLiveChanged(playerId: String, isLive: Bool) {
        emit(
            consumerId: playerId,
            eventType: "liveChanged",
            eventDetails: [
                "live": isLive,
            ]
        )
    }

    func emitPlaybackRateChanged(playerId: String, playbackRate: Double) {
        emit(
            consumerId: playerId,
            eventType: "playbackRateChanged",
            eventDetails: [
                "playbackRate": playbackRate
            ]
        )
    }
    
    func emitVolumeChangedEvent(playerId: String, volume: Double) {
        emit(
            consumerId: playerId,
            eventType: "volumeChanged",
            eventDetails: [
                "volume": volume
            ]
        )
    }
    
    func emitMutedChangedEvent(playerId: String, muted: Bool) {
        emit(
            consumerId: playerId,
            eventType: "mutedChanged",
            eventDetails: [
                "muted": muted
            ]
        )
    }
    
    func emitPlaybackStats(
        playerId: String,
        stats: Stats,
        bufferFullnessSec: Float?
    ) {
        emit(
            consumerId: playerId,
            eventType: "playbackStatsChanged",
            eventDetails: [
                "playbackStats": BridgeSerializer.toPlaybackStats(stats: stats, bufferFullnessSec: bufferFullnessSec)
            ],
            preventDuplicates: false
        )
    }
    
    func emitSeekableRangeChanged(playerId: String, startTimeMs: Int64, endTimeMs: Int64) {
        emit(
            consumerId: playerId,
            eventType: "seekableRangeChanged",
            eventDetails: [
                "startTime": startTimeMs,
                "endTime": endTimeMs
            ]
        )
    }
}
