import AnalyticsClient
import ComposableArchitecture

// swiftlint:disable file_length

extension ContactsAuthorizationAlert {
    struct Analytics: AnalyticsReducer {
        var source: String = "contacts_authorization_alert"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .openSettings:
                track(
                    Event(
                        category: .social,
                        actionName: .settingsOpened
                    )
                )

            case .destination(.presented(.alert(.openSettings))):
                track(
                    Event(
                        category: .social,
                        actionName: .permissionRequestAlertOpenSettingsTapped,
                        actionType: .tap,
                        elementType: .alert
                    )
                )

            case .destination(.presented(.alert(.cancelOpenSettings))):
                track(
                    Event(
                        category: .social,
                        actionName: .permissionRequestAlertCancelOpenSettingsTapped,
                        actionType: .tap,
                        elementType: .alert
                    )
                )

            case .handleAuthorization:
                track(
                    Event(
                        category: .social,
                        actionName: .contactPermissionsChecked,
                        elementType: .alert
                    )
                )

            case .requestPermission:
                track(
                    Event(
                        category: .social,
                        actionName: .contactPermissionsRequested,
                        elementType: .alert
                    )
                )

            case .delegate(.authorized):
                track(
                    Event(
                        category: .social,
                        actionName: .contactPermissionsAllowed
                    )
                )

            case .delegate(.denied):
                track(
                    Event(
                        category: .social,
                        actionName: .contactPermissionsDenied
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension ContactSyncBanner {
    struct Analytics: AnalyticsReducer {
        var source: String = "contact_sync_banner"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .bannerTapped:
                track(
                    Event(
                        category: .social,
                        actionName: .bannerTapped,
                        actionType: .tap,
                        elementType: .banner
                    )
                )

            case .delegate(.dismissTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .dismissTapped,
                        actionType: .tap,
                        elementType: .button
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension FeaturedArtistBanner {
    struct Analytics: AnalyticsReducer {
        var source: String = "featured_artist_banner"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .delegate(.bannerTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .bannerTapped,
                        actionType: .tap,
                        elementType: .banner
                    )
                )

            case .delegate(.dismissTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .dismissTapped,
                        actionType: .tap,
                        elementType: .button
                    )
                )
            }

            return .none
        }
    }
}

extension CreatorsToFollow {
    struct Analytics: AnalyticsReducer {
        var source: String = "creators_to_follow"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .followTapped(let recommendUser):
                if recommendUser.user.isFollowing {
                    track(
                        Event(
                            category: .social,
                            actionName: .unfollowTapped,
                            actionType: .tap,
                            elementType: .button,
                            elementId: recommendUser.id,
                            yIndex: before.recommendedUsers.index(id: recommendUser.id)
                        )
                    )
                } else {
                    track(
                        Event(
                            category: .social,
                            actionName: .followTapped,
                            actionType: .tap,
                            elementType: .button,
                            elementId: recommendUser.id,
                            yIndex: before.recommendedUsers.index(id: recommendUser.id)
                        )
                    )
                }

            case .backButtonTapped:
                track(
                    Event(
                        category: .social,
                        actionName: .backTapped,
                        actionType: .tap,
                        elementType: .toolbarButton
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension FromYourContacts {
    struct Analytics: AnalyticsReducer {
        var source: String = "from_your_contacts"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .inviteTapped(let phoneContact):
                track(
                    Event(
                        category: .social,
                        actionName: .inviteContactTapped,
                        actionType: .tap,
                        elementType: .button,
                        elementId: phoneContact.id,
                        yIndex: before.phoneContacts.index(id: phoneContact.id)
                    )
                )

            case .followTapped(let simpleProfileWithContactName):
                if simpleProfileWithContactName.user.isFollowing {
                    track(
                        Event(
                            category: .social,
                            actionName: .unfollowTapped,
                            actionType: .tap,
                            elementType: .button,
                            elementId: simpleProfileWithContactName.id,
                            yIndex: before.sunoContacts.index(id: simpleProfileWithContactName.id)
                        )
                    )
                } else {
                    track(
                        Event(
                            category: .social,
                            actionName: .followTapped,
                            actionType: .tap,
                            elementType: .button,
                            elementId: simpleProfileWithContactName.id,
                            yIndex: before.sunoContacts.index(id: simpleProfileWithContactName.id)
                        )
                    )
                }

            case .internal(.messageComposeResult(let messageComposeResult)):
                switch messageComposeResult {
                case .cancelled:
                    track(
                        Event(
                            category: .social,
                            actionName: .smsComposeResultCancelled
                        )
                    )

                case .failed:
                    track(
                        Event(
                            category: .social,
                            actionName: .smsComposeResultFailed
                        )
                    )

                case .sent:
                    track(
                        Event(
                            category: .social,
                            actionName: .smsComposeResultSent
                        )
                    )

                @unknown default:
                    break
                }

            case .dismiss:
                track(
                    Event(
                        category: .social,
                        actionName: .dismissed
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension InviteFriendsBanner {
    struct Analytics: AnalyticsReducer {
        var source: String = "invite_friends_banner"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .delegate(.bannerTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .bannerTapped,
                        actionType: .tap,
                        elementType: .banner
                    )
                )

            case .delegate(.dismissTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .dismissTapped,
                        actionType: .tap,
                        elementType: .banner
                    )
                )
            }

            return .none
        }
    }
}

extension PhoneAddNumberInPlatform {
    struct Analytics: AnalyticsReducer {
        var source: String = "phone_add_number_in_platform"

        func analytics(before _: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .internal(.closeButtonTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .closeTapped,
                        actionType: .tap,
                        elementType: .toolbarButton
                    )
                )

            case .internal(.addPhoneNumberResponse(.success(let phoneNumber))):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberSucceeded,
                        elementType: .phoneNumber,
                        elementId: phoneNumber
                    )
                )

            case .internal(.addPhoneNumberResponse(.failure(let error))):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberFailed,
                        elementType: .phoneNumber,
                        context: error.underlyingError
                    )
                )

            default: break
            }

            return .none
        }
    }
}

extension PhoneAddNumber {
    struct Analytics: AnalyticsReducer {
        var source: String = "phone_add_number"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .confirmTapped:
                track(
                    Event(
                        category: .social,
                        actionName: .confirmTapped,
                        actionType: .tap,
                        elementType: .button
                    )
                )

            case .delegate(.phoneCodeSent(let phoneNumber, _)):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneCodeSent,
                        elementType: .phoneNumber,
                        elementId: phoneNumber.e164Formatted
                    )
                )

            case .delegate(.skipTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .skipTapped,
                        actionType: .tap,
                        elementType: .toolbarButton
                    )
                )

            case .internal(.startPhoneValidationResponse(.success(let status))):
                switch status {
                case .oneTimeCodeSent:
                    track(
                        Event(
                            category: .social,
                            actionName: .phoneCodeSent,
                            elementType: .phoneNumber,
                            elementId: before.value
                        )
                    )

                case .validated:
                    track(
                        Event(
                            category: .social,
                            actionName: .phoneNumberAlreadyValidated,
                            elementType: .phoneNumber,
                            elementId: before.value
                        )
                    )
                }

            case .internal(.startPhoneValidationResponse(.failure(let error))):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneNumberValidationFailed,
                        elementType: .phoneNumber,
                        elementId: before.value,
                        context: error.underlyingError
                    )
                )

            case .internal(.addPhoneNumberResponse(.success)):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberSucceeded,
                        elementType: .phoneNumber,
                        elementId: before.value
                    )
                )

            case .internal(.addPhoneNumberResponse(.failure(let error))):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberFailed,
                        elementType: .phoneNumber,
                        elementId: before.value,
                        context: error.underlyingError
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension PhoneCodeEntry {
    struct Analytics: AnalyticsReducer {
        var source: String = "phone_code_entry"

        // swiftlint:disable:next cyclomatic_complexity
        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            let method: String = switch before.path {
            case .addNumber:
                "add_number"
            case .addNumberInPlatform:
                "add_number_in_platform"
            case .signIn:
                "sign_in"
            }

            switch action {
            case .resendTapped:
                track(
                    Event(
                        category: .social,
                        actionName: .resendTapped,
                        actionType: .tap,
                        elementType: .button,
                        method: method,
                        context: before.phoneNumber
                    )
                )

            case .validateCode:
                track(
                    Event(
                        category: .social,
                        actionName: .phoneCodeValidationStarted,
                        elementType: .phoneCode,
                        elementId: before.value,
                        method: method,
                        context: before.phoneNumber
                    )
                )

            case .delegate(.cancelTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .cancelTapped,
                        actionType: .tap,
                        elementType: .toolbarButton,
                        method: method,
                        context: before.phoneNumber
                    )
                )

            case .internal(.validateResponse(.success, authenticationInfo: _)):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneCodeValidationSucceeded,
                        elementType: .phoneCode,
                        elementId: before.value,
                        method: method,
                        context: before.phoneNumber
                    )
                )

            case .internal(.validateResponse(.failure, authenticationInfo: _)):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneCodeValidationFailed,
                        elementType: .phoneCode,
                        elementId: before.value,
                        method: method,
                        context: before.phoneNumber
                    )
                )

            case .internal(.addNumberResponse(.success)):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberSucceeded,
                        elementType: .phoneNumber,
                        elementId: before.phoneNumber
                    )
                )

            case .internal(.addNumberResponse(.failure(let error))):
                track(
                    Event(
                        category: .social,
                        actionName: .addPhoneNumberFailed,
                        elementType: .phoneNumber,
                        context: error.underlyingError
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}

extension PhoneSignIn {
    struct Analytics: AnalyticsReducer {
        let source = "phone_sign_in"

        func analytics(before: State, after _: State, action: Action) -> Effect<Action> {
            switch action {
            case .confirmTapped:
                track(
                    Event(
                        category: .social,
                        actionName: .confirmTapped,
                        actionType: .tap,
                        elementType: .button
                    )
                )

            case .delegate(.cancelTapped):
                track(
                    Event(
                        category: .social,
                        actionName: .cancelTapped,
                        actionType: .tap,
                        elementType: .toolbarButton
                    )
                )

            case .delegate(.phoneCodeSent):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneCodeSent,
                        elementType: .phoneNumber,
                        elementId: before.value
                    )
                )

            case .internal(.sendVerificationCodeResponse(.success)):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneVerificationCodeResponse,
                        elementType: .phoneNumber,
                        elementId: before.value,
                        context: "success"
                    )
                )

            case .internal(.sendVerificationCodeResponse(.failure)):
                track(
                    Event(
                        category: .social,
                        actionName: .phoneVerificationCodeResponse,
                        elementType: .phoneNumber,
                        elementId: before.value,
                        context: "failure"
                    )
                )

            default:
                break
            }

            return .none
        }
    }
}
