import Foundation

extension AnalyticsEvent {
    /// Whitelisted names that act as event action categories
    /// https://us-east-2.console.aws.amazon.com/lambda/home?region=us-east-2#/functions/parse_data?tab=code
    var eventName: String {
        switch self {
        case .onboardingAction:
            "App-Onboarding-Action-Event"
        case .audioAction:
            "App-Audio-Action-Event"
        case .audioCreation:
            "App-Audio-Creation-Event"
        case .general:
            "App-General-Event"
        }
    }
}

/// This protocol allows our event schema to be self-documenting
protocol AnalyticsRoute {
    /// Action name mappings to try to maintain parity with web events:
    /// https://github.com/suno-ai/glockenspiel/blob/f3becefd323223c7145a44c23360cf29b3009124/ui/app-ui/src/utils/event-names.ts
    var actionName: String { get }
    associatedtype P: Codable
    var propertiesType: P.Type { get }
}

extension AnalyticsEvent.OnboardingActionRoute: AnalyticsRoute {
    var actionName: String {
        switch self {
        case .signInWithPhoneTapped:
            return "SignInWithPhoneTapped"
        case .signInWithAppleTapped:
            return "SignInWithAppleTapped"
        case .signInWithGoogleTapped:
            return "SignInWithGoogleTapped"
        case .signInWithMicrosoftTapped:
            return "SignInWithMicrosoftTapped"
        case .signInWithDiscordTapped:
            return "SignInWithDiscordTapped"
        case .userSignedUp:
            return "SignUp"
        case .userLoggedIn:
            return "LogIn"
        case .userLoggedOut:
            return "LogOut"
        }
    }

    struct Properties: Codable {
        let actionName: String
        let userId: String?
        let anonymousId: String
        let sessionId: String?
    }

    var propertiesType: Properties.Type { return Properties.self }
}

extension AnalyticsEvent.AudioActionRoute: AnalyticsRoute {
    var actionName: String {
        switch self {
        // Playback actions
        case .playNewSong:
            return "PlayNewSong"
        case .playSongTapped:
            return "PlaySongTapped"
        case .pauseSongTapped:
            return "PauseSongTapped"
        case .restartSongTapped:
            return "RestartSongTapped"
        case .playNextSong:
            return "PlayNextSong"
        case .playPreviousSong:
            return "PlayPreviousSong"
        case .autoplayNextSong:
            return "AutoplayNextSong"
        case .endOfQueue:
            return "EndOfQueue"
        case .seekFinished:
            return "SeekFinished"
        // Song like / dislike
        case .songLikeTapped:
            return "LikeSong"
        case .songUndoLikeTapped:
            return "UndoLikeSong"
        case .songDislikeTapped:
            return "DislikeSong"
        case .songUndoDislikeTapped:
            return "UndoDislikeSong"
        // Share
        case .shareSongScreenOpened:
            return "ShareSongScreenOpened"
        case .shareSongScreenClosed:
            return "ShareSongScreenClosed"
        case .shareSongTapped:
            return "ShareSongTapped"
        case .songActionsTapped:
            return "SongActionsTapped"
        case .omniplayerExpanded:
            return "OmniplayerExpanded"
        case .omniplayerClosed:
            return "OmniplayerClosed"
        case .omniplayerGenerateMore:
            return "OmniplayerGenerateMore"
        }
    }

    struct Properties: Codable {
        let actionName: String
        let isMobile: Bool
        let clipId: String
        let isPublic: Bool
        let isUserSongOwner: Bool
        let userId: String?
        let isLiked: Bool
        let isDisliked: Bool
        let anonymousId: String
        let shareType: String?
        let isPlaying: Bool?
        let isStreaming: Bool
        let elapsedTime: Float64?
        let totalTime: Float64?
        let fromCommandCenter: Bool?
        let omniplayerIsExpanded: Bool?
        let sessionId: String?
    }

    var shareType: String? {
        if case let .shareSongTapped(shareType) = self {
            return shareType
        }
        return nil
    }

    var propertiesType: Properties.Type { return Properties.self }
}

extension AnalyticsEvent.GeneralRoute: AnalyticsRoute {
    var actionName: String {
        switch self {
        case .inAppReviewPopupShown:
            return "InAppReviewPopupShown"
        case .inAppReviewPopupRatingRequested:
            return "InAppReviewPopupRatingRequested"
        case .inAppReviewPopupDismissed:
            return "InAppReviewPopupDismissed"
        case .contactSyncBannerTapped:
            return "ContactSyncBannerTapped"
        case .contactSyncBannerDismissed:
            return "ContactSyncBannerDismissed"
        case .inviteFriendsBannerTapped:
            return "InviteFriendsBannerTapped"
        case .inviteFriendsBannerDismissed:
            return "InviteFriendsBannerDismissed"
        case .inviteShareTapped:
            return "InviteShareTapped"
        }
    }

    struct Properties: Codable {
        let actionName: String
        let userId: String?
        let anonymousId: String
        /// Maintains a generic value
        /// Our data pipeline requires concrete property fields
        let description: String?
        let sessionId: String?
    }

    var description: String? {
        switch self {
        case .inAppReviewPopupShown(let description),
             .inAppReviewPopupDismissed(let description),
             .inAppReviewPopupRatingRequested(let description),
             .inviteShareTapped(let description):
            return description
        default:
            return nil
        }
    }

    var propertiesType: Properties.Type { return Properties.self }
}
