import APIClient
import CommentsClient
import ComponentLibrary
import ComposableArchitecture
import CoreMedia
import FeatureCaptions
import FeatureComments
import FeatureOmniPlayer
import Foundation
import HooksPlayerClient
import NavigationRouterClient
import OmniPlayerClient
import Utilities

// MARK: Show/hide comments sheet

extension HooksFeedReducer {
    func openCommentsSheet(state: inout State, for hook: Hook) -> Effect<Action> {
        @Dependency(\.commentsClientV2) var commentsSheetClient

        let user = state.me.user
        let hookId = hook.id
        let commentCount = hook.commentCount
        let isAuthorOfHook = hook.user?.id == state.me.user.id

        // Only use cached comments if they match the current hook
        let cachedCommentsState = state.commentsSheetState
        let comments: [CommentEntity]
        let replyCommentsMap: [String: [CommentEntity]]
        let hasMoreRepliesMap: [String: Bool]

        if let cachedState = cachedCommentsState, cachedState.entityId == hookId {
            // Use cached data for the same hook
            comments = cachedState.allSortedUnparentedComments
            replyCommentsMap = cachedState.allSortedRepliesForComment
            hasMoreRepliesMap = cachedState.hasMoreRepliesMap
        } else {
            // Start with empty data for a different hook
            comments = []
            replyCommentsMap = [:]
            hasMoreRepliesMap = [:]
        }

        var authorCaption: AuthorCaption?
        if let caption = hook.caption, !caption.isEmpty {
            authorCaption = AuthorCaption(
                userID: hook.user?.id ?? "",
                userDisplayName: hook.user?.displayName ?? "",
                userAvatarURL: hook.user?.avatarImageUrl,
                content: caption,
                captionMentions: [] // TODO: Add once Hook.captionMentions available
            )
        }

        commentsSheetClient.setCommentsCount(commentCount, hookId, .hook)
        commentsSheetClient.setCommentsActivationState(.activeOnEntity(hook.id, .hook))

        state.destination = .comments(.init(
            authorCaption: authorCaption,
            currentUser: user,
            item: hook,
            isEntityAuthorCurrentUser: isAuthorOfHook,
            comments: comments,
            replyCommentsMap: replyCommentsMap,
            hasMoreRepliesMap: hasMoreRepliesMap,
            elapsedTrackTime: .zero,
            source: state.source
        ))

        // Handle routing into a comment's reply
        if let commentId = state.navigationOptions?.replyToCommentID {
            state.navigationOptions = nil
            return .run { send in
                try await Task.sleep(for: .milliseconds(100))
                await send(.destination(.presented(.comments(.deeplinkIntoReplyForComment(commentId)))))
            }
        } else {
            return .none
        }
    }

    func dismissCommentsSheet(state: inout State) -> Effect<Action> {
        @Dependency(\.commentsClientV2) var commentsSheetClient
        commentsSheetClient.setCommentsActivationState(.notActive)
        state.destination = nil
        return .none
    }
}

// MARK: CommentsClientV2 Event Handler

extension HooksFeedReducer {
    func handleCommentsSheetClientEvent(_ event: CommentsClientV2.Event, state: inout State) -> Effect<Action> {
        switch event {
        case .didUpdateComments(let commentsSheetMap):
            return handleCommentsUpdate(commentsSheetMap, state: &state)
        default:
            return .none
        }
    }

    private func handleCommentsUpdate(_ commentsSheetMap: CommentsSheetMap, state: inout State) -> Effect<Action> {
        guard state.currentIndex >= 0 && state.currentIndex < state.hooks.count else {
            return .none
        }

        let currentHookId = state.hooks[state.currentIndex].id

        // Update comments sheet state
        guard let commentsSheetState = commentsSheetMap.threadForEntity(currentHookId, entityType: .hook) else {
            return .none
        }
        state.commentsSheetState = commentsSheetState

        return updateCommentCountForHook(currentHookId, state: &state)
    }

    private func updateCommentCountForHook(_ hookId: String, state _: inout State) -> Effect<Action> {
        return .run { send in
            @Dependency(\.hooksPlayerClient) var hooksPlayerClient
            @Shared(.inMemory(.commentsSheetCountMap)) var commentsCountMap: CommentsTotalCountMap = .defaultValue
            let count = commentsCountMap.commentCountForEntity(hookId, entityType: .hook)

            if case .known(let commentCount) = count {
                await hooksPlayerClient.setCommentCount(commentCount, hookId)
                await send(.syncFromCache(hookIds: [hookId], handles: []))
            }
        }
    }
}
