import APIClient
import ComponentLibrary
import ComposableArchitecture
import CoreMedia
import Errors
import Foundation
import Localization
import LyricsClient
import OmniPlayerClient
import RequestState
import ShareAssetClient
import StatsigClient
import Utilities
import Waveform

@Reducer
public struct AssetCreationReducer {
    public typealias State = AssetCreationState

    public enum Action: BindableAction {
        case visualizerGallery(VisualizerGalleryReducer.Action)

        case task
        case pauseShareAssetAudio
        case stopShareAssetAudio
        case playShareAssetAudioAtTime(_ time: TimeInterval)
        case delegate(Delegate)
        case binding(BindingAction<AssetCreationReducer.State>)

        public enum Delegate {
            case startCreationWithConfig(
                _ config: VisualizerAssetConfig,
                assetTarget: ShareAssetCreationTarget,
                triggerID: String, /* Different than asset ID so we don't have to wait for asset ID response from backend */
                startTime: TimeInterval,
                endTime: TimeInterval
            )
        }
    }

    public init() {}

    @Dependency(APIClient.self) var api
    @Dependency(\.shareAssetClient) var shareAssetClient
    @Dependency(\.omniplayerClient) var omniplayerClient

    public var body: some ReducerOf<Self> {
        BindingReducer()

        Scope(state: \.visualizerGallery, action: \.visualizerGallery) {
            VisualizerGalleryReducer()
        }

        Reduce { state, action in
            struct ShareAssetEventStreamCancellable: Hashable {}

            switch action {
            case .task:
                omniplayerClient.pauseCurrentClip()
                return .none

            case .pauseShareAssetAudio:
                state.assetCreationPlayer.pause()
                return .none

            case .stopShareAssetAudio:
                state.assetCreationPlayer.stop()
                return .none

            case .playShareAssetAudioAtTime(let time):
                let player = state.assetCreationPlayer
                let cmTime = CMTime(seconds: time, preferredTimescale: 1000)
                return .run { [player, cmTime] send in
                    await player.playAtTime(cmTime)
                }

            case .visualizerGallery(.delegate(.shareSavedVideo(let localAssetURL))):
                shareAssetClient.shareToDestination(
                    shareURL: state.shareURL,
                    videoURL: localAssetURL,
                    pngStickerData: .init(),
                    linkMessage: L10n.FeatureShare.shareSongSubject,
                    shareDestination: state.targetDestination
                )
                return .none

            case .visualizerGallery(.delegate(.playAudioAtTime(let time))):
                return .send(.playShareAssetAudioAtTime(time))

            case .visualizerGallery(.delegate(.seekTime(let time, let isMuted))):
                guard !isMuted else { return .none }
                return .send(.playShareAssetAudioAtTime(time))

            case .visualizerGallery(.delegate(.pauseAudio)):
                return .send(.pauseShareAssetAudio)

            case .visualizerGallery(.delegate(.startRenderWithSelectedConfig(let config, let startTime, let endTime))):
                let triggerID = UUID().uuidString
                state.selectedConfig = config
                shareAssetClient.triggerCreateShareAsset(
                    state.clip,
                    triggerID,
                    config.shareAssetConfig,
                    startTime,
                    endTime,
                    state.shareURL,
                    state.targetDestination
                )

                return .concatenate(
                    .send(.delegate(.startCreationWithConfig(
                        config,
                        assetTarget: state.targetDestination,
                        triggerID: triggerID,
                        startTime: startTime,
                        endTime: endTime
                    ))),
                    .send(.stopShareAssetAudio)
                )

            case .visualizerGallery:
                return .none

            case .binding:
                return .none

            case .delegate:
                return .none
            }
        }
    }
}
