import Foundation

/*
 All the different playback context sources. This is used to tell us the `source` in
 `SessionContext`, which only has a couple of other properties for now, but could definitely
 add some more in the future. This references the doc found here:
    https://docs.google.com/document/d/1n72SbgeW_XwhaW61vzrGoEwwd2UxKhkoE-FI27DGGVY/edit?tab=t.q47u1bp7li5a

 Currently, the only remaining items are:
    - song_reference_clip (when clicking on "Remix Of" in OmniPlayer and eventually Feed)
    - style_tag (from Styles on Explore/Discover)
 */

public enum ContextSource: Equatable, Sendable {
    // TODO: Add search filters
    case search

    case hooksFeed
    case profile(id: String, filters: [ProfileFilter] = [])

    case myHooks
    case notification(notificationId: String?)

    // Only used for Hooks and Clips, but can support Playlists and Profiles in the future
    case deeplink(entityId: String, entityType: DeeplinkEntityType)

    // When navigating from a clip to another clip, like in the "See more" section
    // in the OmniPlayer. Or, when navigating from a clip to a Hook, like in
    // "View Hooks" in the ExpandedPlayer (OmniPlayer).
    case clip(clipId: String)

    case hookActionsMenu(hookId: String)
    case songCapsule(hookId: String)
    case remixOfSheet(parentClipId: String)
    case topClips(handle: String)

    // When tapping on the banner to play new gens, or on the Hooks toast after
    // posting successfully (TODO)
    case topToast

    // The uploads drawer that users can access in Create with Audio
    case audioLibraryPicker

    case library(filters: [LibraryFilter] = [])
    case playlist(playlistId: String)
    case remix(parentClipId: String)
    case style(styleId: String)

    // Explore/Discover
    case trending(filters: [TrendingFilter])
    case listenHistory
    case featuredFeed(id: String)
    case discoverCarousel(id: String)
    case contest(clipId: String)
    case promo(id: String)

    case unknown // For cases where we can't determine the source

    public enum DeeplinkEntityType: String, Codable, Equatable, Sendable {
        case clip
        case hook
        case playlist
        case profile
    }

    public enum LibraryFilter: String, Codable, Equatable, Sendable {
        case `public`
        case `private`
        case liked
    }

    public enum ProfileFilter: String, Codable, Equatable, Sendable {
        case hooks
    }

    public enum TrendingFilter: Codable, Equatable, Sendable {
        case language(String)
        case period(String)
        
        public var description: String {
            switch self {
            case .language(let language):
                return language
            case .period(let period):
                return period
            }
        }
    }

    // This helps us determine pagination behavior when setting up
    // a Hooks feed in `HooksFeedReducer`
    public var canFetchMoreHooks: Bool {
        switch self {
        case .deeplink, .notification, .unknown:
            return false
        default:
            return true
        }
    }

    public var shouldPlayInHooksTab: Bool {
        switch self {
        case .hooksFeed, .deeplink:
            return true
        default:
            return false
        }
    }

    public var analyticsContext: (contextType: String, contextId: String?) {
        switch self {
        case .hooksFeed:
            return ("hooks_feed", nil)

        case .myHooks:
            return ("library", nil)

        case .clip(let clipId):
            return ("clip", clipId)

        case .notification(let notificationId):
            return ("notification", notificationId)

        case .deeplink(let entityId, let entityType):
            return (entityType.rawValue, entityId)

        case .profile(let id, _):
            // Add profile filters once we have more than one destination
            // within another users profile (in the future)
            return ("profile", id)

        case .library(let filters):
            let mappedFilters = filters.map { $0.rawValue }.joined(separator: "|")
            let cleanFilters = mappedFilters.trimmingCharacters(in: CharacterSet(charactersIn: "|"))
            return ("library", cleanFilters.isEmpty ? nil : cleanFilters)

        case .topToast:
            return ("top_toast", nil)

        case .unknown:
            return ("unknown", nil)

        case .playlist(playlistId: let playlistId):
            return ("playlist", playlistId)

        case .remix(parentClipId: let parentClipId):
            return ("remix", parentClipId)

        case .style(styleId: let styleId):
            return ("style", styleId)

        case .trending(let filters):
            let mappedFilters = filters.map { $0.description }.joined(separator: "|")
            let cleanFilters = mappedFilters.trimmingCharacters(in: CharacterSet(charactersIn: "|"))
            return ("trending", cleanFilters.isEmpty ? nil : cleanFilters)

        case .listenHistory:
            return ("listen_history", nil)

        case .featuredFeed(let id):
            return ("featured_feed", id)

        case .discoverCarousel(let id):
            return ("discover_carousel", id)

        case .contest(let clipId):
            return ("contest", clipId)

        case .promo(let id):
            return ("promo", id)

        case .hookActionsMenu(hookId: let hookId):
            return ("hook_actions_menu", hookId)

        case .songCapsule(hookId: let hookId):
            return ("song_capsule", hookId)

        case .remixOfSheet(parentClipId: let parentClipId):
            return ("remix_of", parentClipId)

        case .topClips(handle: let handle):
            return ("top_clips", handle)

        case .audioLibraryPicker:
            return ("audio_library_picker", nil)

        case .search:
            return ("search", nil)
        }
    }
}
