import Foundation

public struct Event: Codable {
    /// Action category i.e. general, onboarding, create
    public let category: Category
    /// Name of the action
    public let actionName: ActionName
    /// i.e. tap, swipe, toggle
    public let actionType: ActionType
    /// i.e. button, song, playlist, artist, banner, popup
    public let elementType: ElementType
    /// The id associated with the thing you're clicking on (the object), i.e.
    public let elementId: String?
    /// i.e. the text of the style tag selected
    public let elementText: String?
    /// Use when it's important for clicks on screens that have order i.e. playlists, carousels
    public let xIndex: Int?
    /// i.e. taps on lists
    public let yIndex: Int?
    /// i.e. email, link, x (for sharing), google, phone (for signin)
    public let method: String?
    /// The rule for when something happens i.e. a popup
    public let condition: String?
    /// General field to provide context i.e. other metadata
    public let context: String?
    /// i.e. up, down, left, right
    public let direction: String?
    /// i.e. a list of 2 created clips, or a playlist
    public let createdId: String?
    /// if this was a revenue based event, the value of the associated item
    public let revenueAmount: Double?
    /// if this was a revenue based event, the currency of the associated item
    public let revenueCurrency: String?

    /// Active user id. `nil` if not authenticated yet
    var userId: String?
    /// User's device id. Should almost never be `nil`, supplied by Segment
    var anonymousId: String?
    /// Supplied by our APIClient middleware via network responses, which serializes this to an `@Shared` property
    var sessionId: String?
    /// Name of the currently active screen.
    var screenName: String?
    /// If the screen subject is a song/playlist/user, add the id of that element here
    var screenElementId: String?
    /// Name of the source of the event. Used to identify the event in code i.e. `root_coordinator` or `create_clip`
    var source: String?

    public init(
        category: Category,
        actionName: ActionName,
        actionType: ActionType = .event,
        elementType: ElementType = .none,
        elementId: String? = nil,
        elementText: String? = nil,
        xIndex: Int? = nil,
        yIndex: Int? = nil,
        method: String? = nil,
        condition: String? = nil,
        context: String? = nil,
        direction: String? = nil,
        createdId: String? = nil,
        source: String? = nil,
        revenueAmount: Double? = nil,
        revenueCurrency: String? = nil
    ) {
        self.category = category
        self.actionName = actionName
        self.actionType = actionType
        self.xIndex = xIndex
        self.yIndex = yIndex
        self.method = method
        self.elementType = elementType
        self.elementId = elementId
        self.elementText = elementText
        self.condition = condition
        self.context = context
        self.direction = direction
        self.createdId = createdId
        self.source = source
        self.revenueAmount = revenueAmount
        self.revenueCurrency = revenueCurrency
    }
}

public extension Event {
    var asDictionary: [String: Any] {
        var dict: [String: Any] = [
            "category": category.rawValue,
            "action_name": actionName.rawValue,
            "action_type": actionType.rawValue,
            "element_type": elementType.rawValue,
        ]

        if let elementId = elementId {
            dict["element_id"] = elementId
        }
        if let elementText = elementText {
            dict["element_text"] = elementText
        }
        if let xIndex = xIndex {
            dict["x_index"] = xIndex
        }
        if let yIndex = yIndex {
            dict["y_index"] = yIndex
        }
        if let method = method {
            dict["method"] = method
        }
        if let condition = condition {
            dict["condition"] = condition
        }
        if let context = context {
            dict["context"] = context
        }
        if let direction = direction {
            dict["direction"] = direction
        }
        if let createdId = createdId {
            dict["created_id"] = createdId
        }
        if let userId = userId {
            dict["user_id"] = userId
        }
        if let anonymousId = anonymousId {
            dict["anonymous_id"] = anonymousId
        }
        if let sessionId = sessionId {
            dict["session_id"] = sessionId
        }
        if let screenName = screenName {
            dict["screen_name"] = screenName
        }
        if let screenElementId = screenElementId {
            dict["screen_element_id"] = screenElementId
        }
        if let source = source {
            dict["source"] = source
        }
        if let revenueAmount {
            dict["revenue_amount"] = revenueAmount
        }
        if let revenueCurrency {
            dict["revenue_currency"] = revenueCurrency
        }

        return dict
    }
}

public extension Event {
    enum Category: String, Codable {
        case general
        case onboarding
        case create
        case social
        case profile
        case audioPlayer = "audio_player"
        case settings
        case inAppNotifications = "in_app_notifications"
        case share
        case deeplinking
        case clipDetails = "clip_details"
        case promo
        case omniPlayer = "omni_player"
        case hooksPlayer = "hooks_player"
        case songActions = "song_actions"
        case sorting
        case navigation
        case hooksCreate = "hooks_create"
        case hooksPost = "hooks_post"
    }

    enum ActionType: String, Codable {
        case event
        case tap
        case toggle
        case swipe
        case alert
        case longPress = "long_press"
        case textEntry = "text_entry"
        case scroll
        case drag
    }

    enum ElementType: String, Codable {
        case none
        case button
        case banner
        case alert
        case notification
        case toolbarButton = "toolbar_button"
        case listRow = "list_row"
        case toast
        case profile
        case phoneNumber = "phone_number"
        case phoneCode = "phone_code"
        case user
        case permissions
        case displayName = "display_name"
        case handle
        case clip
        case clipOrPlaylist = "clip_or_playlist"
        case playlist
        case hook
        case carousel
        case url
        case timeInterval = "time_interval"
        case uploadRequestId = "upload_request_id"
        case uploadRequestStatus = "upload_request_status"
        case audio
        case lyrics
        case image
        case video
        case camera
        case tab
        case textField = "text_field"
        case status
        case linkText
        case promoCard = "promo_card"
        case snippet
        case waveform
        case slider
        case toggle
        case hookPreview = "hook_preview"
    }
}
