import BackendEnvironmentClient
import ComposableArchitecture
import DebugUtilities
import Foundation
import SwiftUI

#if canImport(DebugMenu)
    import DebugMenu
#endif

#if canImport(RageshakeClient)
    import RageshakeClient
#endif

public struct DebugFeatureActions {
    public let showOnboarding: () -> Void
    public let showMadlibsOnboarding: () -> Void
    public let showHooksCreate: () -> Void
    public let showNotificationQuestion: () -> Void
    public let showOrpheusCustomCreate: () -> Void
    public let showOrpheusCustomCreateCover: () -> Void

    public init(
        showOnboarding: @escaping () -> Void,
        showMadlibsOnboarding: @escaping () -> Void,
        showHooksCreate: @escaping () -> Void,
        showNotificationQuestion: @escaping () -> Void,
        showOrpheusCustomCreate: @escaping () -> Void,
        showOrpheusCustomCreateCover: @escaping () -> Void
    ) {
        self.showOnboarding = showOnboarding
        self.showMadlibsOnboarding = showMadlibsOnboarding
        self.showHooksCreate = showHooksCreate
        self.showNotificationQuestion = showNotificationQuestion
        self.showOrpheusCustomCreate = showOrpheusCustomCreate
        self.showOrpheusCustomCreateCover = showOrpheusCustomCreateCover
    }
}

public enum DebugRageshakeUser: Equatable {
    case authenticated(id: String, email: String, displayName: String?, handle: String)
    case anonymous
}

public extension DebugRageshakeUser {
    var userId: String? {
        switch self {
        case let .authenticated(id, _, _, _):
            return id
        case .anonymous:
            return nil
        }
    }
}

@DependencyClient
public struct DebugFeatureClient: Sendable {
    public var isDebugMenuAvailable: @Sendable () -> Bool = { false }
    public var makeOverlay: @Sendable (_ actions: DebugFeatureActions) -> AnyView?
    public var setRageshakeEnabled: @Sendable (_ isEnabled: Bool) -> Void
    public var setRageshakeUser: @Sendable (DebugRageshakeUser) -> Void
    public var registerNetworkingInterception: @Sendable (URLSessionConfiguration) -> Void
    public var showRageshake: @Sendable () -> Void
    public var postAnalyticsEvent: @Sendable (DebugAnalyticsEvent) -> Void
}

public extension DebugFeatureClient {
    static let noop = Self(
        isDebugMenuAvailable: { false },
        makeOverlay: { _ in nil },
        setRageshakeEnabled: { _ in },
        setRageshakeUser: { _ in },
        registerNetworkingInterception: { _ in },
        showRageshake: {},
        postAnalyticsEvent: { _ in }
    )
}

extension DebugFeatureClient: DependencyKey {
    public static let liveValue: Self = {
        guard BackendEnvironmentProvider.isStaffBuild() else {
            return .noop
        }

        #if canImport(DebugMenu) && canImport(RageshakeClient)
            @Dependency(RageshakeClient.self) var rageshakeClient

            return DebugFeatureClient(
                isDebugMenuAvailable: {
                    DebugMenu.isAllowed
                },
                makeOverlay: { actions in
                    guard DebugMenu.isAllowed else { return nil }

                    let mappedActions = DebugMenuView.Actions(
                        showOnboarding: actions.showOnboarding,
                        showMadlibsOnboarding: actions.showMadlibsOnboarding,
                        showHooksCreate: actions.showHooksCreate,
                        showNotificationQuestion: actions.showNotificationQuestion,
                        showOrpheusCustomCreate: actions.showOrpheusCustomCreate,
                        showOrpheusCustomCreateCover: actions.showOrpheusCustomCreateCover
                    )

                    return AnyView(DebugMenuView(actions: mappedActions))
                },
                setRageshakeEnabled: { isEnabled in
                    rageshakeClient.setIsEnabled(isEnabled)
                },
                setRageshakeUser: { user in
                    switch user {
                    case let .authenticated(id, email, displayName, handle):
                        rageshakeClient.setUser(.authenticated(.init(
                            id: id,
                            email: email,
                            displayName: displayName,
                            handle: handle
                        )))
                    case .anonymous:
                        rageshakeClient.setUser(.anonymous)
                    }
                },
                registerNetworkingInterception: { configuration in
                    rageshakeClient.registerNetworkingInterception(configuration)
                },
                showRageshake: {
                    rageshakeClient.show()
                },
                postAnalyticsEvent: { event in
                    DebugAnalyticsEvent.postDebugNotification(event)
                }
            )
        #else
            return .noop
        #endif
    }()

    public static let previewValue = Self.noop
    public static let testValue = Self.noop
}
