import APIClient
import Foundation
import Localization
import SwiftUI
import Utilities

/// SwiftUI overlay for video cells with debug information
public struct HookVideoOverlay: View {
    let hook: Hook
    let index: Int
    let isVisible: Bool
    let playbackState: PlaybackState
    let showFollowButton: Bool
    let isFollowing: Bool
    let isLiked: Bool
    let isClipLiked: Bool
    let likeCount: Int
    let commentCount: Int
    let clipPlayCount: Int
    let lyrics: LyricsDataV2
    let isReported: Bool
    let isCreatorHidden: Bool
    let heartAnimationTrigger: Int // Shows animation when user double-taps to like
    let shouldDimButtons: Bool
    let isFocused: Bool
    let shouldDisableButtons: Bool
    let isMuted: Bool

    // Work around to acurately handle playback time updates.
    // Handling playback time updates via SlidingWindowState was causes severe performance issues.
    let overlayPlaybackViewModel: OverlayPlaybackViewModel

    private let maxHeartAnimationsFromDoubleTap = 5
    @State private var activeHeartAnimations: Set<UUID> = []
    @State private var hapticProxy: Int = 0
    // this is used to toggle showing and hiding the HookBlurOverlay for when the hook is reported inappropriate or creator is hidden
    @State private var isReportOverlayHidden: Bool = false

    @State private var lyricsOverlaySize: CGSize = .zero
    private let lyricsCenterAligned: Bool

    @State private var hookVideoOverlaySize: CGSize = .zero

    // Action callbacks
    let onRemixTapped: (Hook) -> Void
    let onLikeTapped: (Hook) -> Void
    let onFollowTapped: (Hook) -> Void
    let onShareTapped: (Hook) -> Void
    let onCommentsTapped: (Hook) -> Void
    let onMoreTapped: (Hook) -> Void
    let onAuthorTapped: (String) -> Void
    let onAddSongTapped: (Hook) -> Void
    let onChangePlaylistTapped: (Hook) -> Void
    let onSongTapped: (Clip) -> Void
    let onPlayTapped: () -> Void
    let onShowReportedHookTapped: ((String) -> Void)?
    let onTapToUnmute: () -> Void

    public init(
        hook: Hook,
        index: Int,
        isVisible: Bool,
        playbackState: PlaybackState,
        showFollowButton: Bool,
        isFollowing: Bool = false,
        isLiked: Bool = false,
        isClipLiked: Bool = false,
        likeCount: Int = 0,
        commentCount: Int = 0,
        clipPlayCount: Int = 0,
        overlayPlaybackViewModel: OverlayPlaybackViewModel,
        lyrics: LyricsDataV2 = .empty,
        isReported: Bool = false,
        isCreatorHidden: Bool = false,
        heartAnimationTrigger: Int = 0,
        onRemixTapped: @escaping (Hook) -> Void,
        onLikeTapped: @escaping (Hook) -> Void,
        onFollowTapped: @escaping (Hook) -> Void,
        onShareTapped: @escaping (Hook) -> Void,
        onCommentsTapped: @escaping (Hook) -> Void,
        onMoreTapped: @escaping (Hook) -> Void,
        onAuthorTapped: @escaping (String) -> Void,
        onAddSongTapped: @escaping (Hook) -> Void,
        onChangePlaylistTapped: @escaping (Hook) -> Void,
        onSongTapped: @escaping (Clip) -> Void,
        onPlayTapped: @escaping () -> Void,
        onShowReportedHookTapped: ((String) -> Void)? = nil,
        shouldDimButtons: Bool = false,
        isFocused: Bool = false,
        shouldDisableButtons: Bool = false,
        isMuted: Bool = true,
        onTapToUnmute: @escaping () -> Void
    ) {
        self.hook = hook
        self.index = index
        self.isVisible = isVisible
        self.playbackState = playbackState
        self.showFollowButton = showFollowButton
        self.isFollowing = isFollowing
        self.isLiked = isLiked
        self.isClipLiked = isClipLiked
        self.likeCount = likeCount
        self.commentCount = commentCount
        self.clipPlayCount = clipPlayCount
        self.overlayPlaybackViewModel = overlayPlaybackViewModel
        self.lyrics = lyrics
        self.isReported = isReported
        self.isCreatorHidden = isCreatorHidden
        self.heartAnimationTrigger = heartAnimationTrigger
        self.onRemixTapped = onRemixTapped
        self.onLikeTapped = onLikeTapped
        self.onFollowTapped = onFollowTapped
        self.onShareTapped = onShareTapped
        self.onCommentsTapped = onCommentsTapped
        self.onMoreTapped = onMoreTapped
        self.onAuthorTapped = onAuthorTapped
        self.onAddSongTapped = onAddSongTapped
        self.onChangePlaylistTapped = onChangePlaylistTapped
        self.onSongTapped = onSongTapped
        self.onPlayTapped = onPlayTapped
        self.onShowReportedHookTapped = onShowReportedHookTapped
        self.shouldDimButtons = shouldDimButtons
        self.isFocused = isFocused
        self.shouldDisableButtons = shouldDisableButtons
        self.isMuted = isMuted
        self.onTapToUnmute = onTapToUnmute
        self.lyricsCenterAligned = hook.lyricDisplay == .centeredLine || hook.lyricDisplay == .centeredWord
    }

    public var body: some View {
        ZStack {
            VStack(spacing: .zero) {
                HStack(spacing: .zero) {
                    VStack(alignment: .leading, spacing: 8) {
                        if !lyricsCenterAligned {
                            timeSyncedLyricsView
                        }

                        userAndCaption
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
                    .contentShape(Rectangle())
                    .readSize(to: $lyricsOverlaySize)

                    actionBar
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
                .padding([.horizontal, .bottom], 12)

                songCapsule
            }
            .readSize(to: $hookVideoOverlaySize)
        }
        .overlay {
            if lyricsCenterAligned {
                timeSyncedLyricsView
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
                    .offset(y: -hookVideoOverlaySize.height * 0.05)
                    .ignoresSafeArea()
            }
        }
        .overlay {
            // Heart icon on double-tap, play icon when paused, etc.
            fullScreenOverlay
                .ignoresSafeArea()
        }
        .background {
            if isMuted, isFocused {
                // Show a dimmed black overlay when muted (on app launch)
                Color.black.opacity(0.5)
                    .ignoresSafeArea()
            }
        }
        .ignoresSafeArea()
    }

    @ViewBuilder
    private var fullScreenOverlay: some View {
        ZStack {
            heartAnimationsOverlay
                .disabled(shouldDisableButtons)

            if isVisible,
               playbackState == .paused,
               activeHeartAnimations.isEmpty,
               isFocused
            {
                playButtonOverlay
                    .transition(.blurReplace)
            }

            blurOverlay

            if isMuted, isFocused {
                TapToUnmuteOverlay(onTap: { onTapToUnmute() })
                    .transition(.blurReplace)
            }
        }
        .animation(.bouncy(extraBounce: 0.3), value: activeHeartAnimations)
        .animation(.bouncy(extraBounce: 0.3), value: isMuted)
        .animation(.bouncy(duration: 0.3), value: playbackState)
        .sensoryFeedbackIfEnabled(.selection, trigger: hapticProxy)
        .onChange(of: heartAnimationTrigger) { _, _ in
            // We're passing this trigger in from HookVideoCell and handling
            // multi-taps on that layer instead because I couldn't figure out
            // how to add it to this SwiftUI layer without adding a delay to all the button taps.
            triggerHeartAnimation()
        }
        .onChange(of: isReported) { _, newValue in
            // Reset the overlay hidden state when reported status changes
            // This ensures the overlay reappears when re-reporting
            if newValue {
                isReportOverlayHidden = false
            }
        }
    }

    private func triggerHeartAnimation() {
        let heartId = UUID()
        guard activeHeartAnimations.count < maxHeartAnimationsFromDoubleTap else { return }
        activeHeartAnimations.insert(heartId)
        hapticProxy += 1
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) {
            activeHeartAnimations.remove(heartId)
        }
    }

    @ViewBuilder
    private var blurOverlay: some View {
        if isReported && !isReportOverlayHidden {
            HookBlurOverlayView(
                titleText: L10n.FeatureHooks.thanksForReportingHook,
                descriptionText: L10n.FeatureHooks.reportingHookFeedbackDescription,
                buttonAction: {
                    isReportOverlayHidden = true
                    onShowReportedHookTapped?(hook.id)
                },
                buttonText: L10n.FeatureHooks.showPost
            )
        } else if isCreatorHidden {
            HookBlurOverlayView(
                titleText: L10n.FeatureHooks.creatorHiddenTitle,
                descriptionText: L10n.FeatureHooks.creatorHiddenDescription,
                buttonAction: nil,
                buttonText: nil
            )
        }
    }

    @ViewBuilder
    private var heartAnimationsOverlay: some View {
        ForEach(Array(activeHeartAnimations), id: \.self) { heartId in
            AnimatedDoubleTapHeart(id: heartId)
        }
    }

    @ViewBuilder
    private var playButtonOverlay: some View {
        if #available(iOS 26.0, *) {
            Button(action: {
                onPlayTapped()
            }) {
                Image.Icon.playFilled
                    .resizable()
                    .frame(width: 32, height: 32)
                    .foregroundColor(Color.SemanticV2.foregroundPrimary)
                    .frame(width: 64, height: 64)
                    .glassEffect(.regular.interactive())
            }
        } else {
            Button(action: {
                onPlayTapped()
            }) {
                Circle()
                    .fill(.ultraThinMaterial)
                    .frame(width: 64, height: 64)
                    .overlay {
                        Image.Icon.playFilled
                            .resizable()
                            .frame(width: 32, height: 32)
                            .foregroundColor(Color.SemanticV2.foregroundPrimary)
                    }
            }
        }
    }

    private var buttonOverlayOpacity: Double {
        if isFocused {
            return 1.0
        } else if shouldDimButtons || shouldDisableButtons {
            return 0.5
        } else {
            return 0.0
        }
    }

    private var textOverlayOpacity: Double {
        if isFocused {
            return 1.0
        } else if shouldDimButtons || shouldDisableButtons {
            return 0.5
        } else {
            return 0.0
        }
    }

    @ViewBuilder
    private var actionBar: some View {
        HookVideoCellActionBar(
            hook: hook,
            isFollowing: isFollowing,
            isLiked: isLiked,
            likeCount: likeCount,
            commentCount: commentCount,
            onRemixTapped: onRemixTapped,
            onLikeTapped: onLikeTapped,
            onProfileTapped: onAuthorTapped,
            onFollowTapped: onFollowTapped,
            onShareTapped: onShareTapped,
            onCommentsTapped: onCommentsTapped,
            onMoreTapped: onMoreTapped
        )
        .opacity(buttonOverlayOpacity)
        .disabled(shouldDisableButtons)
        .animation(.easeInOut(duration: 0.3), value: buttonOverlayOpacity)
    }

    @State private var isCaptionExpanded: Bool = false

    @ViewBuilder
    private var userAndCaption: some View {
        VStack(alignment: .leading, spacing: 8) {
            if let user = hook.user, !user.displayName.isEmpty {
                HStack(spacing: 8) {
                    Button(action: { onAuthorTapped(user.handle) }) {
                        HStack {
                            avatarImage(user: user)
                            Text(user.displayName)
                                .typographyV1(.body1.size { _ in 16.0 }.lineHeight(18.0).kerning(0.32))
                                .foregroundStyle(.white)
                        }
                        .contentShape(Rectangle())
                    }

                    if showFollowButton {
                        HookFollowPill(
                            isFollowing: isFollowing,
                            followTapped: {
                                onFollowTapped(hook)
                            }
                        )
                    }
                }
                .frame(height: 22) // Height of the follow button
            }
            if let caption = hook.caption, !caption.isEmpty {
                ExpandableText(
                    InteractiveTextFormatter.formatCaptionText(
                        caption,
                        mentions: [],
                        config: .playerCaption
                    ),
                    font: .playerCaption,
                    condensedLineLimit: 2,
                    isExpanded: $isCaptionExpanded
                )
                .onUserMentionTapped { _ in }
            }
        }
        .foregroundStyle(.white)
        .frame(maxWidth: .infinity, alignment: .bottomLeading)
        .padding(.trailing, 22)
        .contentShape(Rectangle())
        .opacity(textOverlayOpacity)
        .disabled(shouldDisableButtons)
        .animation(.easeInOut(duration: 0.3), value: textOverlayOpacity)
    }

    @ViewBuilder
    private var songCapsule: some View {
        HookVideoCellSongCapsule(
            hook: hook,
            playbackState: playbackState,
            isClipLiked: isClipLiked,
            clipPlayCount: clipPlayCount,
            onAddSongTapped: { hook in
                onAddSongTapped(hook)
            },
            onChangePlaylistTapped: { hook in
                onChangePlaylistTapped(hook)
            },
            onSongTapped: onSongTapped
        )
        .opacity(buttonOverlayOpacity)
        .disabled(shouldDisableButtons)
        .animation(.easeInOut(duration: 0.3), value: buttonOverlayOpacity)
    }

    @ViewBuilder
    private func avatarImage(user: SimpleProfile) -> some View {
        if let avatarUrl = user.avatarImageUrl, !avatarUrl.isEmpty {
            Circle()
                .fill(Material.ultraThinMaterial)
                .overlay {
                    ZStack {
                        RemoteImage(url: avatarUrl, fallbackId: nil)
                            .frame(width: 26, height: 26)
                            .clipShape(Circle())
                        Circle().strokeBorder(
                            Color.SemanticV2.backgroundFogDense,
                            lineWidth: 0.5
                        )
                        .frame(width: 26, height: 26)
                    }
                }
        }
    }

    private var shouldShowLyrics: Bool {
        // Only hide lyrics when truly stopped (navigating away, etc.)
        // This prevents lyrics from flashing during fast scrolling when cell is created with .notReady state
        let isPlaybackStopped = playbackState == .stopped
        guard !isPlaybackStopped, hook.showLyrics, lyrics != .empty else {
            return false
        }
        return true
    }

    @ViewBuilder
    private var timeSyncedLyricsView: some View {
        if shouldShowLyrics {
            let lyricDisplay = hook.lyricDisplay ?? .bottomLeftLine

            HookVideoLyricsOverlay(
                lyrics: lyrics,
                snippetStart: hook.startClipTimestamp,
                snippetEnd: hook.endClipTimestamp,
                isPaused: playbackState != .playing,
                lyricDisplay: lyricDisplay,
                containerSize: lyricsOverlaySize,
                overlayPlaybackViewModel: overlayPlaybackViewModel
            )
            .transition(.opacity)
            .opacity(textOverlayOpacity)
            .animation(.easeInOut(duration: 0.3), value: textOverlayOpacity)
        }
    }
}

// TODO: Revist possibly moving this playback time updates to publisher events w/ HooksPlayerEvent
/// Observable model for smooth playback timing without full UI refreshes.
/// Per-cell AVPlayer observers + @Published playbackTime provides better performance
/// than sending HooksPlayerEvent from SlidingWindowState.
public final class OverlayPlaybackViewModel: ObservableObject {
    @Published public var playbackTime: Double = 0.0

    public init(_ playbackTime: Double = 0.0) {
        self.playbackTime = playbackTime
    }
}
