import APIClient
import AsyncAlgorithms
import Combine
import ComposableArchitecture
import Foundation
import StatsigClient

@DependencyClient
public struct EventBusClient {
    // https://forums.swift.org/t/creating-a-dependency-from-apolloclient/61185/3
    // This pattern is used as generics /Users/jimmyyue/workspace/app-ios/Sources/EventBusClient/Events.swift aren't supported in `DependencyClient`s

    // DEPRECATED: Old AsyncChannel approach
    // Use Combine publishers instead
    public var getOmniplayerChannel: () -> AsyncChannel<OmniPlayerEvent> = { AsyncChannel() }
    public var getCreateChannel: () -> AsyncChannel<CreateEvent> = {
        AsyncChannel()
    }

    public var getBillingChannel: () -> AsyncChannel<BillingEvent> = {
        AsyncChannel()
    }

    // New Combine publisher approach
    // See `Effect+Extensions` for `.subscribe`
    // Look into migrating to Sendable / Swift 6
    public var sendClipEvent: (_ event: ClipEvent) -> Void
    public var getClipPublisher: () -> AnyPublisher<ClipEvent, Never> = { Empty().eraseToAnyPublisher() }

    public var sendHookEvent: (_ event: HookEvent) -> Void
    public var getHookPublisher: () -> AnyPublisher<HookEvent, Never> = { Empty().eraseToAnyPublisher() }

    public var sendProfileEvent: (_ event: ProfileEvent) -> Void
    public var getProfilePublisher: () -> AnyPublisher<ProfileEvent, Never> = { Empty().eraseToAnyPublisher() }

    public var sendModalEvent: (_ event: ModalEvent) -> Void
    public var getModalPublisher: () -> AnyPublisher<ModalEvent, Never> = { Empty().eraseToAnyPublisher() }
    
    public var sendDeeplinkEvent: (_ event: DeeplinkEvent) -> Void
    public var getDeeplinkPublisher: () -> AnyPublisher<DeeplinkEvent, Never> = { Empty().eraseToAnyPublisher() }
}

extension EventBusClient: DependencyKey {
    public static var liveValue: EventBusClient {
        let omniplayerChannel = AsyncChannel<OmniPlayerEvent>()
        let createChannel = AsyncChannel<CreateEvent>()
        let billingChannel = AsyncChannel<BillingEvent>()

        let clipPublisher = PassthroughSubject<ClipEvent, Never>()
        let hookPublisher = PassthroughSubject<HookEvent, Never>()
        let profilePublisher = PassthroughSubject<ProfileEvent, Never>()
        let modalPublisher = PassthroughSubject<ModalEvent, Never>()
        let deeplinkPublisher = PassthroughSubject<DeeplinkEvent, Never>()

        return Self(
            getOmniplayerChannel: { omniplayerChannel },
            getCreateChannel: { createChannel },
            getBillingChannel: { billingChannel },
            sendClipEvent: { event in
                clipPublisher.send(event)
            },
            getClipPublisher: {
                clipPublisher
                    .share()
                    .eraseToAnyPublisher()
            },
            sendHookEvent: { event in
                hookPublisher.send(event)
            },
            getHookPublisher: {
                hookPublisher
                    .share()
                    .eraseToAnyPublisher()
            },
            sendProfileEvent: { event in
                profilePublisher.send(event)
            },
            getProfilePublisher: {
                profilePublisher
                    .share()
                    .eraseToAnyPublisher()
            },
            sendModalEvent: { event in
                modalPublisher.send(event)
            },
            getModalPublisher: {
                modalPublisher
                    .share()
                    .eraseToAnyPublisher()
            },
            sendDeeplinkEvent: { event in
                deeplinkPublisher.send(event)
            },
            getDeeplinkPublisher: {
                deeplinkPublisher
                    .share()
                    .eraseToAnyPublisher()
            }
        )
    }
}

public extension DependencyValues {
    var eventBus: EventBusClient {
        get { self[EventBusClient.self] }
        set { self[EventBusClient.self] = newValue }
    }
}
