import AnalyticsClient
import APIClient
import AVFoundation
import CommentsClient
import ComponentLibrary
import ComposableArchitecture
import FeatureClipDetail
import Foundation
import MediaPlayer
import StatsigClient
import SwiftUI

public struct ExpandedPlayerPlaybar: View {
    @Shared var playerState: OmniPlayerPlaybackState
    let clip: Clip
    let shouldDimProgressBar: Bool
    let shouldHideControls: Bool
    let playTapped: () -> Void
    let pauseTapped: () -> Void
    let nextTapped: () -> Void
    let prevTapped: () -> Void
    let didStartScrubbing: (CMTime) -> Void
    let didEndScrubbing: (CMTime) -> Void

    // Command center properties
    static var commandCenter: MPRemoteCommandCenter?
    static var commandCenterSetup: Bool = false

    public init(
        playerState: Shared<OmniPlayerPlaybackState>,
        clip: Clip,
        shouldDimProgressBar: Bool = false,
        shouldHideControls: Bool = false,
        playTapped: @escaping () -> Void,
        pauseTapped: @escaping () -> Void,
        nextTapped: @escaping () -> Void,
        prevTapped: @escaping () -> Void,
        didStartScrubbing: @escaping (CMTime) -> Void,
        didEndScrubbing: @escaping (CMTime) -> Void
    ) {
        self._playerState = playerState
        self.clip = clip
        self.shouldDimProgressBar = shouldDimProgressBar
        self.shouldHideControls = shouldHideControls
        self.playTapped = playTapped
        self.pauseTapped = pauseTapped
        self.nextTapped = nextTapped
        self.prevTapped = prevTapped
        self.didStartScrubbing = didStartScrubbing
        self.didEndScrubbing = didEndScrubbing
        // Setup command center when initialized
        ExpandedPlayerPlaybar.setupCommandCenter(
            playFromCommandCenter: playTapped,
            pauseFromCommandCenter: pauseTapped,
            nextFromCommandCenter: nextTapped,
            prevFromCommandCenter: prevTapped,
            seekFromCommandCenter: didEndScrubbing
        )
    }

    // Setup command center with appropriate targets
    private static func setupCommandCenter(
        playFromCommandCenter: @escaping () -> Void,
        pauseFromCommandCenter: @escaping () -> Void,
        nextFromCommandCenter: @escaping () -> Void,
        prevFromCommandCenter: @escaping () -> Void,
        seekFromCommandCenter: @escaping (CMTime) -> Void
    ) {
        guard !commandCenterSetup else { return }
        commandCenterSetup = true

        let commandCenter = MPRemoteCommandCenter.shared()

        // Remove any existing targets
        commandCenter.playCommand.removeTarget(nil)
        commandCenter.pauseCommand.removeTarget(nil)
        commandCenter.nextTrackCommand.removeTarget(nil)
        commandCenter.previousTrackCommand.removeTarget(nil)
        commandCenter.changePlaybackPositionCommand.removeTarget(nil)

        // Add new targets
        commandCenter.playCommand.addTarget { _ in
            playFromCommandCenter()
            return .success
        }

        commandCenter.pauseCommand.addTarget { _ in
            pauseFromCommandCenter()
            return .success
        }

        commandCenter.nextTrackCommand.addTarget { _ in
            nextFromCommandCenter()
            return .success
        }

        commandCenter.previousTrackCommand.addTarget { _ in
            prevFromCommandCenter()
            return .success
        }

        commandCenter.changePlaybackPositionCommand.addTarget { event in
            guard let event = event as? MPChangePlaybackPositionCommandEvent else { return .commandFailed }
            let time = CMTime(seconds: event.positionTime, preferredTimescale: CMTimeScale(1000))
            seekFromCommandCenter(time)
            return .success
        }

        // Enable all commands
        commandCenter.playCommand.isEnabled = true
        commandCenter.pauseCommand.isEnabled = true
        commandCenter.nextTrackCommand.isEnabled = true
        commandCenter.previousTrackCommand.isEnabled = true
        commandCenter.changePlaybackPositionCommand.isEnabled = true

        ExpandedPlayerPlaybar.commandCenter = commandCenter
    }

    private let transitionCurve = Animation.timingCurve(0.65, 0, 0.35, 1, duration: 0.2)

    private var disableNextButton: Bool {
        (playerState.isPlayingNewGeneration || playerState.source == .hooksFeed) && playerState.isAtEndOfQueue
    }

    private var disablePreviousButton: Bool {
        playerState.isPlayingNewGeneration && playerState.isAtStartOfQueue
    }

    public var body: some View {
        VStack(spacing: .zero) {
            progressBar
            if !shouldHideControls {
                controls
                    .opacity(playerState.isScrubbing ? 0.2 : 1)
                    .animation(transitionCurve, value: playerState.isScrubbing)
                    .fixedSize(horizontal: false, vertical: true)
                    .transition(.scale(scale: 0.9).combined(with: .offset(y: 36).combined(with: .opacity)))
            }
        }
        .opacity(clip.id != playerState.clip.id ? 0.8 : 1)
        .animation(transitionCurve, value: shouldHideControls)
    }

    private var controls: some View {
        HStack(spacing: 32) {
            previousButton
            playPauseButton
            nextButton
        }
        .frame(maxWidth: .infinity)
        .fixedSize(horizontal: false, vertical: true)
    }

    @ViewBuilder
    private var nextButton: some View {
        Image.Omniplayer.nextTrack
            .resizable()
            .frame(width: 36, height: 36)
            .foregroundColor(.SemanticV1.iconPrimary)
            .frame(width: 40, height: 40)
            .contentShape(Rectangle())
            .onTapGesture {
                nextTapped()
            }
            // Once the work for shuffle and repeat is complete, we can read the playback configuration
            // directly instead of relying on `isPlayingNewGeneration`
            .opacity(disableNextButton ? 0.4 : 1.0)
            .disabled(disableNextButton)
    }

    @ViewBuilder
    private var previousButton: some View {
        Image.Omniplayer.previousTrack
            .resizable()
            .frame(width: 36, height: 36)
            .foregroundColor(.SemanticV1.iconPrimary)
            .frame(width: 40, height: 40)
            .contentShape(Rectangle())
            .onTapGesture {
                prevTapped()
            }
            .opacity(disablePreviousButton ? 0.4 : 1.0)
            .disabled(disablePreviousButton)
    }

    @ViewBuilder
    private var playPauseButton: some View {
        ExpandedPlayerPlayPauseButton(
            playTapped: playTapped,
            pauseTapped: pauseTapped,
            timeControlStatus: playerState.timeControlStatus
        )
    }

    private var totalTimeAnimation: Animation? {
        // Only animate if we're playing new gens
        guard playerState.isPlayingNewGeneration else { return nil }
        return .easeInOut(duration: 0.3)
    }

    @ViewBuilder
    private var progressBar: some View {
        VStack(spacing: .zero) {
            ExpandedPlayerProgressViewV2(
                totalTime: playerState.totalTime,
                fallbackTotalTimeSeconds: playerState.fallbackTotalTimeSeconds,
                displayTime: playerState.displayTime,
                timeControlStatus: playerState.timeControlStatus,
                onScrubStart: didStartScrubbing,
                onScrubComplete: didEndScrubbing
            )
            .frame(height: 28)
            ZStack {
                Text(playerState.displayTime.seconds.positionalTime)
                    .typographyV1(.caption6.inputSans())
                    .foregroundStyle(Color.SemanticV2.foregroundTertiaryGlass)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .shadow(color: Color.SemanticV2.backgroundGlassDense, radius: 4)
                Text(playerState.displayedTotalTime)
                    .typographyV1(.caption6.inputSans())
                    .foregroundStyle(Color.SemanticV2.foregroundTertiaryGlass)
                    .contentTransition(.numericText())
                    .animation(totalTimeAnimation, value: playerState.displayedTotalTime)
                    .frame(maxWidth: .infinity, alignment: .trailing)
                    .shadow(color: Color.SemanticV2.backgroundGlassDense, radius: 4)
            }
            .frame(height: 16)
        }
        .opacity(shouldDimProgressBar ? 0.3 : 1.0)
        .animation(.spring(response: 0.6, dampingFraction: 0.8), value: shouldDimProgressBar)
        .disabled(shouldDimProgressBar)
    }

    @ViewBuilder
    private var totalTime: some View {
        Text("\(playerState.totalTime.seconds.positionalTime)")
            .typographyV1(.monospace)
            .foregroundStyle(Color.SemanticV1.textPrimary)
            .padding(.leading, 14)
    }
}
