import AnalyticsClient
import ComposableArchitecture

// swiftlint:disable file_length

// MARK: Blended Create

/// ** Note: Blended Create Scenes / Camera Events use the legacy `CreateClipCamera` analytics events

extension BlendedCreate {
    struct Analytics: AnalyticsReducer {
        var source: String = "blended_create"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .audio(.delegate(.didPressAudioLengthUpsell)):
                track(
                    Event(
                        category: .promo,
                        actionName: .audioLengthUpsellTapped,
                        actionType: .tap,
                        elementType: .linkText
                    )
                )

            default:
                break
            }
            return .none
        }
    }
}

// MARK: Legacy Create

extension CreateClipCamera {
    struct Analytics: AnalyticsReducer {
        var source: String = "create_clip_v2_camera"

        // swiftlint:disable:next cyclomatic_complexity function_body_length
        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            // Note: This event currently fires *twice* for every camera shutter capture.
            case .tookImage:
                track(
                    Event(
                        category: .create,
                        actionName: .imageCaptured,
                        elementType: .image
                    )
                )

            case .importedImage:
                track(
                    Event(
                        category: .create,
                        actionName: .imageImported,
                        elementType: .image
                    )
                )

            case .tookVideo:
                track(
                    Event(
                        category: .create,
                        actionName: .videoCaptured,
                        elementType: .video
                    )
                )

            case .importedVideo:
                track(
                    Event(
                        category: .create,
                        actionName: .videoImported,
                        elementType: .video
                    )
                )

            case .setFlash(let flashEnabled):
                track(
                    Event(
                        category: .create,
                        actionName: .cameraFlashSet,
                        elementType: .camera,
                        method: flashEnabled.toString()
                    )
                )

            case .toggleFlash:
                if before.flash {
                    track(
                        Event(
                            category: .create,
                            actionName: .disableCameraFlashTapped,
                            actionType: .tap,
                            elementType: .camera
                        )
                    )
                } else {
                    track(
                        Event(
                            category: .create,
                            actionName: .enableCameraFlashTapped,
                            actionType: .tap,
                            elementType: .camera
                        )
                    )
                }

            case .didSelectImage:
                track(
                    Event(
                        category: .create,
                        actionName: .mediaPickerImageSelected,
                        actionType: .tap,
                        elementType: .image
                    )
                )

            case .didSelectMovie:
                track(
                    Event(
                        category: .create,
                        actionName: .mediaPickerVideoSelected,
                        actionType: .tap,
                        elementType: .video
                    )
                )

            case .delegate(.showAlert(let brandedAlertStyle)):
                let context: String = switch brandedAlertStyle {
                case .noAlert:
                    "no_alert"
                case .announceAlert(let announceAlertStyle):
                    announceAlertStyle.textCopy.toString()
                case .singleButtonAlert(let singleButtonAlertStyle):
                    singleButtonAlertStyle.textCopy.toString()
                case .multiButtonAlert(let multiButtonAlertStyle):
                    multiButtonAlertStyle.toString()
                case .listAlert(let listAlertStyle):
                    listAlertStyle.textCopy.toString()
                case .featuredArtist(let featuredArtistStyle):
                    featuredArtistStyle.textCopy.toString()
                case .versioningAlert(let versioningAlertStyle):
                    versioningAlertStyle.textCopy.toString()
                case .discountAlert(let discountAlertStyle):
                    discountAlertStyle.analyticsAttribute.toString()
                case .walkthroughAlert(let walkthroughAlertStyle):
                    walkthroughAlertStyle.textCopy.toString()
                case .hookStatusAlert(let hookStatusAlertStyle):
                    hookStatusAlertStyle.textCopy.toString()
                }

                track(
                    Event(
                        category: .create,
                        actionName: .showBrandedAlert,
                        elementType: .alert,
                        context: context
                    )
                )

            case .presentMediaPicker:
                track(
                    Event(
                        category: .create,
                        actionName: .mediaPickerTapped,
                        actionType: .tap,
                        elementType: .camera
                    )
                )

            case .dismissMediaPicker:
                track(
                    Event(
                        category: .create,
                        actionName: .mediaPickerDismissed,
                        elementType: .camera
                    )
                )

            case .presentVideoTrimmer:
                track(
                    Event(
                        category: .create,
                        actionName: .videoTrimmerPresented
                    )
                )

            case .dismissVideoTrimmer:
                track(
                    Event(
                        category: .create,
                        actionName: .videoTrimmerDismissed
                    )
                )

            default:
                break
            }
            return .none
        }
    }
}

extension ClipImageReducer {
    struct Analytics: AnalyticsReducer {
        var source: String = "create_clip_v2_camera_image"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .didTapCreate:
                let imageSource: String = switch before.image {
                case .local:
                    "local"
                case .remote:
                    "remote"
                }
                track(
                    Event(
                        category: .create,
                        actionName: .createTapped,
                        actionType: .tap,
                        elementType: .button,
                        method: imageSource,
                        context: PromptMetadata(
                            text: before.caption,
                            type: "IMAGE",
                            modelMajorVersion: before.selectedSunoModel.majorVersion
                        ).toString()
                    ),
                    destination: .all
                )

            default:
                break
            }
            return .none
        }
    }
}

extension ClipVideoReducer {
    struct Analytics: AnalyticsReducer {
        var source: String = "create_clip_v2_camera_video"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .togglePlayPause:
                if before.isPlaying {
                    track(
                        Event(
                            category: .create,
                            actionName: .pauseTapped,
                            actionType: .tap,
                            elementType: .button
                        )
                    )
                } else {
                    track(
                        Event(
                            category: .create,
                            actionName: .playTapped,
                            actionType: .tap,
                            elementType: .button
                        )
                    )
                }

            case .didTapCreate:
                track(
                    Event(
                        category: .create,
                        actionName: .createTapped,
                        actionType: .tap,
                        elementType: .button,
                        context: PromptMetadata(
                            text: before.caption,
                            type: "VIDEO",
                            modelMajorVersion: before.selectedSunoModel.majorVersion
                        ).toString()
                    ),
                    destination: .all
                )

            case .didTapDismiss:
                track(
                    Event(
                        category: .create,
                        actionName: .dismissTapped,
                        actionType: .tap,
                        elementType: .button
                    )
                )

            case .setAudioMode(let mode):
                let audioMode: String = switch mode {
                case .existing:
                    "existing"
                case .replace:
                    "replace"
                }
                track(
                    Event(
                        category: .create,
                        actionName: .audioModeSet,
                        actionType: .tap,
                        elementType: .button,
                        method: audioMode
                    )
                )

            case .videoReachedEnd:
                track(
                    Event(
                        category: .create,
                        actionName: .videoReachedEndTime,
                        elementType: .video,
                        context: before.duration?.seconds.toString()
                    )
                )

            default:
                break
            }
            return .none
        }
    }
}

// Convenience method used to convert the prompt metadata into a string for analytics
// This could be moved to a computed property on Prompt if it keeps growing, but we'd
// have to import APIClient into this file
public struct PromptMetadata: Codable {
    public let text: String
    public let type: String
    public let modelMajorVersion: Int
    public let task: String?

    public init(
        text: String,
        type: String,
        modelMajorVersion: Int,
        task: String? = nil
    ) {
        self.text = text
        self.type = type
        self.modelMajorVersion = modelMajorVersion
        self.task = task
    }
}
