import AnalyticsClient
import AttributionAndDeeplinkingClient
import Dependencies
import FeatureMadlibsOnboardingModels
import FeatureOnboardingModels
import Foundation
import StatsigClient

// MARK: - OnboardingAnalyticsClient

public struct OnboardingAnalyticsClient {
    // Core onboarding events
    public var trackFlowStarted: @Sendable (_ flowVariant: OnboardingFlowVariant, _ userId: String?) -> Void
    public var trackFlowCompleted: @Sendable (_ flowVariant: OnboardingFlowVariant, _ userId: String?, _ isFirstTimeUser: Bool) -> Void
    public var trackScreenView: @Sendable (_ stepType: OnboardingStepType, _ flowVariant: OnboardingFlowVariant, _ userId: String?) -> Void

    // Welcome screen events
    public var trackWelcomePageAppeared: @Sendable () -> Void
    public var trackSignUpTapped: @Sendable () -> Void
    public var trackSignInTapped: @Sendable () -> Void

    // Loading events
    public var trackLoadCurrentUserStarted: @Sendable () -> Void

    // Authentication events
    public var trackAuthMethodSelected: @Sendable (_ method: SignInMethod?, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackPhoneCodeSent: @Sendable (_ phoneNumber: String, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackAuthSucceeded: @Sendable (_ flowVariant: OnboardingFlowVariant, _ isFirstTimeUser: Bool) -> Void
    public var trackAuthFailed: @Sendable (_ error: String?, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackSignUpSucceeded: @Sendable (_ flowVariant: OnboardingFlowVariant, _ userId: String) -> Void

    // Profile setup events
    public var trackUpdateDisplayNameTapped: @Sendable (_ currentValue: String?, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackDisplayNameUpdated: @Sendable (_ success: Bool, _ displayName: String?, _ error: String?, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackUpdateHandleTapped: @Sendable (_ flowVariant: OnboardingFlowVariant) -> Void
    public var trackUsernameUpdated: @Sendable (_ success: Bool, _ username: String?, _ error: String?, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackBirthdayUpdated: @Sendable (_ flowVariant: OnboardingFlowVariant) -> Void

    // Permission events
    public var trackNotificationPermissionRequested: @Sendable (_ flowVariant: OnboardingFlowVariant, _ fromScreen: OnboardingStepType) -> Void
    public var trackNotificationPermissionResult: @Sendable (_ allowed: Bool, _ flowVariant: OnboardingFlowVariant, _ fromScreen: OnboardingStepType) -> Void
    public var trackContactPermissionRequested: @Sendable (_ flowVariant: OnboardingFlowVariant) -> Void
    public var trackContactPermissionResult: @Sendable (_ allowed: Bool, _ flowVariant: OnboardingFlowVariant) -> Void

    // User actions
    public var trackSkipTapped: @Sendable (_ fromScreen: OnboardingStepType, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackBackTapped: @Sendable (_ fromScreen: OnboardingStepType, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackCancelTapped: @Sendable (_ onScreen: OnboardingStepType, _ flowVariant: OnboardingFlowVariant) -> Void
    public var trackDoneTapped: @Sendable (_ fromScreen: OnboardingStepType, _ flowVariant: OnboardingFlowVariant) -> Void

    // Madlibs event tracking
    public var trackMadlibsEvent: @Sendable (_ event: MadlibsAnalyticsEvent) -> Void
}

// MARK: - Dependency

public extension DependencyValues {
    var onboardingAnalyticsClient: OnboardingAnalyticsClient {
        get { self[OnboardingAnalyticsClient.self] }
        set { self[OnboardingAnalyticsClient.self] = newValue }
    }
}

// MARK: - SignInMethod

private extension SignInMethod {
    var analyticsName: String {
        switch self {
        case .phone: "phone"
        case .apple: "apple"
        case .google: "google"
        case .microsoft: "microsoft"
        case .discord: "discord"
        }
    }
}

// MARK: - Helper Methods

private extension OnboardingFlowVariant {
    /// Returns a formatted context string for analytics tracking
    /// - Parameter additionalContext: Optional additional context to append
    /// - Returns: A formatted string like "flow_variant:default" or "flow_variant:madlibs_additional_context"
    func analyticsContext(
        with additionalContext: String? = nil
    ) -> String {
        if let additionalContext {
            return "flow_variant:\(rawValue)_\(additionalContext)"
        } else {
            return "flow_variant:\(rawValue)"
        }
    }
}

// MARK: - Implementation

extension OnboardingAnalyticsClient: DependencyKey {
    public static let liveValue = {
        let analyticsSource = "onboarding_analytics_client"

        return OnboardingAnalyticsClient(
            trackFlowStarted: { flowVariant, userId in
                @Dependency(\.analyticsClient) var analyticsClient
                @Dependency(StatsigClient.self) var statsigClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .onboardingFlowStarted,
                        elementType: .user,
                        elementId: userId,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .all
                )

                // Also track Statsig event
                if let userId {
                    statsigClient.trackEvent(.onboardingStarted(
                        stableID: statsigClient.getStableID(),
                        sunoUserID: userId
                    ))
                }
            },

            trackFlowCompleted: { flowVariant, userId, _ in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .onboardingFlowFinished,
                        elementType: .user,
                        elementId: userId,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackScreenView: { stepType, flowVariant, userId in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = stepType.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .viewAppeared,
                        actionType: .event,
                        elementType: .none,
                        elementId: userId,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackWelcomePageAppeared: {
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .welcomePageAppeared
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackSignUpTapped: {
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .signUpTapped,
                        actionType: .tap,
                        elementType: .button
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackSignInTapped: {
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .signInTapped,
                        actionType: .tap,
                        elementType: .button
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackLoadCurrentUserStarted: {
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .loadCurrentUserStarted,
                        elementType: .user
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackAuthMethodSelected: { method, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .authMethodTapped,
                        actionType: .tap,
                        elementType: .button,
                        method: method?.analyticsName ?? "unknown",
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackPhoneCodeSent: { phoneNumber, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .phoneCodeSent,
                        elementType: .phoneNumber,
                        elementId: phoneNumber,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackAuthSucceeded: { flowVariant, isFirstTimeUser in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .authSucceeded,
                        context: flowVariant.analyticsContext(with: isFirstTimeUser ? "signup" : "login")
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackAuthFailed: { error, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .authFailed,
                        context: flowVariant.analyticsContext(with: error ?? "unknown")
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackSignUpSucceeded: { flowVariant, userId in
                @Dependency(\.analyticsClient) var analyticsClient
                @Dependency(AttributionAndDeeplinkingClient.self) var attributionAndDeeplinkingClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .signUpSucceeded,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .all
                )
                attributionAndDeeplinkingClient.track(.signUp(sunoUserId: userId))
            },

            trackUpdateDisplayNameTapped: { currentValue, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .updateDisplayNameTapped,
                        actionType: .tap,
                        elementType: .button,
                        context: currentValue ?? flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackDisplayNameUpdated: { success, displayName, error, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let actionName: Event.ActionName = success ? .updateDisplayNameSucceeded : .updateDisplayNameFailed

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: actionName,
                        elementType: .displayName,
                        elementId: displayName,
                        context: error ?? flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackUpdateHandleTapped: { _ in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .updateHandleTapped,
                        actionType: .tap,
                        elementType: .button
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackUsernameUpdated: { success, username, error, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let actionName: Event.ActionName = success ? .updateHandleSucceeded : .updateHandleFailed

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: actionName,
                        elementType: .handle,
                        elementId: username,
                        context: error ?? flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackBirthdayUpdated: { flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .birthdayUpdateCompleted,
                        actionType: .tap,
                        elementType: .button,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackNotificationPermissionRequested: { flowVariant, fromScreen in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = fromScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .notificationsPermissionsRequested,
                        actionType: .alert,
                        elementType: .alert,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackNotificationPermissionResult: { allowed, flowVariant, fromScreen in
                @Dependency(\.analyticsClient) var analyticsClient

                let actionName: Event.ActionName = allowed ? .notificationsPermissionsAllowed : .notificationsPermissionsDenied
                let screenName = fromScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: actionName,
                        actionType: .alert,
                        elementType: .alert,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .all
                )
            },

            trackContactPermissionRequested: { flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .contactsAuthorizationAlertShown,
                        actionType: .alert,
                        elementType: .alert,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackContactPermissionResult: { allowed, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let actionName: Event.ActionName = allowed ? .contactPermissionsAllowed : .contactPermissionsDenied

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: actionName,
                        elementType: .permissions,
                        context: flowVariant.analyticsContext()
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackSkipTapped: { fromScreen, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = fromScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .skipTapped,
                        actionType: .tap,
                        elementType: .button,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackBackTapped: { fromScreen, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = fromScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .backTapped,
                        actionType: .tap,
                        elementType: .button,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackCancelTapped: { onScreen, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = onScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .cancelTapped,
                        actionType: .tap,
                        elementType: .toolbarButton,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackDoneTapped: { fromScreen, flowVariant in
                @Dependency(\.analyticsClient) var analyticsClient

                let screenName = fromScreen.analyticsName

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: .doneTapped,
                        actionType: .tap,
                        elementType: .toolbarButton,
                        context: flowVariant.analyticsContext(with: screenName),
                        source: screenName
                    ),
                    source: analyticsSource,
                    destination: .standard
                )
            },

            trackMadlibsEvent: { event in
                @Dependency(\.analyticsClient) var analyticsClient

                analyticsClient.trackV2(
                    event: Event(
                        category: .onboarding,
                        actionName: event.actionName,
                        actionType: event.actionType,
                        elementType: event.elementType,
                        elementId: event.elementId,
                        elementText: event.elementText,
                        context: event.context
                    ),
                    source: analyticsSource
                )
            }
        )
    }()
}

public extension OnboardingAnalyticsClient {
    static let testValue = OnboardingAnalyticsClient(
        trackFlowStarted: { _, _ in },
        trackFlowCompleted: { _, _, _ in },
        trackScreenView: { _, _, _ in },
        trackWelcomePageAppeared: {},
        trackSignUpTapped: {},
        trackSignInTapped: {},
        trackLoadCurrentUserStarted: {},
        trackAuthMethodSelected: { _, _ in },
        trackPhoneCodeSent: { _, _ in },
        trackAuthSucceeded: { _, _ in },
        trackAuthFailed: { _, _ in },
        trackSignUpSucceeded: { _, _ in },
        trackUpdateDisplayNameTapped: { _, _ in },
        trackDisplayNameUpdated: { _, _, _, _ in },
        trackUpdateHandleTapped: { _ in },
        trackUsernameUpdated: { _, _, _, _ in },
        trackBirthdayUpdated: { _ in },
        trackNotificationPermissionRequested: { _, _ in },
        trackNotificationPermissionResult: { _, _, _ in },
        trackContactPermissionRequested: { _ in },
        trackContactPermissionResult: { _, _ in },
        trackSkipTapped: { _, _ in },
        trackBackTapped: { _, _ in },
        trackCancelTapped: { _, _ in },
        trackDoneTapped: { _, _ in },
        trackMadlibsEvent: { _ in }
    )
}
