import AVFoundation
import ComponentLibrary
import Foundation
import MediaPlayer
import SwiftUI

public struct PlayPauseButtonV2: View {
    private enum Constants {
        static let buttonSize: CGFloat = 48
        static let iconSize: CGFloat = 28
        static let playIconPadding: CGFloat = 2 // Used to visually center the play icon
    }

    var timeControlStatus: AVPlayer.TimeControlStatus
    var play: () -> Void
    var pause: () -> Void
    var playFromCommandCenter: () -> Void
    var pauseFromCommandCenter: () -> Void
    var nextFromCommandCenter: () -> Void
    var prevFromCommandCenter: () -> Void
    var likeFromCommandCenter: () -> Void
    var unlikeFromCommandCenter: () -> Void
    var seekFromCommandCenter: (CMTime) -> Void

    static var commandCenter: MPRemoteCommandCenter?
    static var commandCenterSetup: Bool = false

    public init(
        timeControlStatus: AVPlayer.TimeControlStatus,
        isLiked: Bool,
        hasNextTrack: Bool,
        hasPrevTrack: Bool,
        play: @escaping () -> Void,
        pause: @escaping () -> Void,
        playFromCommandCenter: @escaping () -> Void,
        pauseFromCommandCenter: @escaping () -> Void,
        nextFromCommandCenter: @escaping () -> Void,
        prevFromCommandCenter: @escaping () -> Void,
        likeFromCommandCenter: @escaping () -> Void,
        unlikeFromCommandCenter: @escaping () -> Void,
        seekFromCommandCenter: @escaping (CMTime) -> Void
    ) {
        self.timeControlStatus = timeControlStatus
        self.play = play
        self.pause = pause
        self.playFromCommandCenter = playFromCommandCenter
        self.pauseFromCommandCenter = pauseFromCommandCenter
        self.nextFromCommandCenter = nextFromCommandCenter
        self.prevFromCommandCenter = prevFromCommandCenter
        self.likeFromCommandCenter = likeFromCommandCenter
        self.unlikeFromCommandCenter = unlikeFromCommandCenter
        self.seekFromCommandCenter = seekFromCommandCenter

        PlayPauseButtonV2.setupCommandCenter(self)
        PlayPauseButtonV2.commandCenter?.likeCommand.isActive = isLiked
        PlayPauseButtonV2.commandCenter?.nextTrackCommand.isEnabled = hasNextTrack
        PlayPauseButtonV2.commandCenter?.previousTrackCommand.isEnabled = hasPrevTrack
    }

    private static func setupCommandCenter(_ instance: Self) {
        guard !commandCenterSetup else { return }
        commandCenterSetup = true
        let commandCenter = MPRemoteCommandCenter.shared()

        commandCenter.playCommand.addTarget { _ in
            instance.playFromCommandCenter()
            return .success
        }

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

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

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

        commandCenter.likeCommand.addTarget { _ in
            instance.likeFromCommandCenter()
            commandCenter.likeCommand.isActive = true
            return .success
        }

        commandCenter.dislikeCommand.addTarget { _ in
            instance.unlikeFromCommandCenter()
            commandCenter.likeCommand.isActive = false
            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))
            instance.seekFromCommandCenter(time)
            return .success
        }

        PlayPauseButtonV2.commandCenter = commandCenter
    }

    @State var transparency = 0.0

    public var body: some View {
        let isPlaying = timeControlStatus == .playing
        Button {
            switch timeControlStatus {
            case .paused:
                play()
            case .waitingToPlayAtSpecifiedRate:
                pause()
            case .playing:
                pause()
            @unknown default:
                break
            }
            transparency = 0.4
            Task {
                try? await Task.sleep(for: .seconds(0.1))
                transparency = 0.0
            }

            UIImpactFeedbackGenerator(style: .light).impactOccurred()
        } label: {
            ZStack {
                Circle()
                    .fill(.ultraThinMaterial)
                    .frame(width: 48, height: 48)
                    .opacity(transparency)
                    .environment(\.colorScheme, .light)
                    .animation(.easeInOut(duration: 0.1), value: transparency)

                if timeControlStatus != .waitingToPlayAtSpecifiedRate {
                    Image.Icon.playFilled
                        .frame(width: Constants.iconSize, height: Constants.iconSize)
                        .foregroundColor(.SemanticV1.iconPrimary)
                        .scaleEffect(isPlaying ? 0 : 1)
                        .opacity(isPlaying ? 0 : 1)
                        .padding(.trailing, Constants.playIconPadding)

                    Image.Icon.pause
                        .frame(width: Constants.iconSize, height: Constants.iconSize)
                        .foregroundColor(.SemanticV1.iconPrimary)
                        .scaleEffect(isPlaying ? 1 : 0)
                        .opacity(isPlaying ? 1 : 0)
                } else {
                    Image.Icon.pause
                        .frame(width: Constants.iconSize, height: Constants.iconSize)
                        .foregroundColor(.SemanticV1.iconPrimary)
                }
            }
            .frame(width: 48, height: 48)
            .contentShape(Circle())
        }
        .foregroundColor(.primary)
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
    }
}
