import ComponentLibrary
import ComposableArchitecture
import FeatureClipDetail
import FeatureComments
import FeatureShareSheet
import Localization
import StatsigClient
import SwiftUI

private extension TypographyV1 {
    /// size: 18pt, lineHeight: 24pt, weight: medium, kerning: 0.02
    static let body5: TypographyV1 = .init(
        name: "Body 5",
        size: 18,
        style: .body,
        weight: .ppNeueMontrealMedium,
        kerning: 0.02,
        lineHeight: 24
    )

    /// size: 16pt, lineHeight: 24pt, weight: regular, kerning: 0.02
    static let body6: TypographyV1 = .init(
        name: "Body 6",
        size: 18,
        style: .body,
        weight: .ppNeueMontrealRegular,
        kerning: 0.02,
        lineHeight: 24
    )
}

public struct ExpandedPlayerView: View {
    // Note: The expanded player forces the dark mode environment.
    // You'll see the `.environment(\.colorScheme, .dark)` line at the bottom of this view.
    @Bindable var store: StoreOf<ExpandedPlayerReducer>

    // This will be used to fade content in and out as the user scrolls up and down ExpandedPlayerView
    @State var verticalScrollPosition: CGFloat = 0
    @Shared var playerState: OmniPlayerPlaybackState
    @State private var scrollDownTrigger: Int = 0
    @State private var scrollToTopTrigger: Int = 0
    private var isDraggingOmniPlayer: Bool {
        @Shared(.inMemory(.omniPlayerDragOffset)) var dragOffset: CGFloat = 0
        return dragOffset != 0
    }

    private var shouldDisableVerticalScrolling: Bool {
        store.player.isScrubbing || store.showNewSongsTooltip || isDraggingOmniPlayer
    }

    // This sends a callback to the parent OmniPlayerView when the user is trying swipe down
    // to collapse the expanded player while at the top of the scroll view.
    private let dragOffsetWhileAtTop: (CGFloat) -> Void

    // offset between the ExpandedPlayerClipDetails and ExpandedPlayerChrome
    private let clipDetailsChromeOffset: CGFloat = -70

    let isVisible: Bool

    public init(
        store: StoreOf<ExpandedPlayerReducer>,
        isVisible: Bool = true,
        dragOffsetWhileAtTop: @escaping (CGFloat) -> Void
    ) {
        self.store = store
        self.isVisible = isVisible
        self.dragOffsetWhileAtTop = dragOffsetWhileAtTop
        self._playerState = store.$player
    }

    public var body: some View {
        content
            .sheet(item: $store.scope(state: \.destination?.comments, action: \.destination.comments)) {
                store.send(.commentsDismissed)
            } content: { store in
                CommentsThreadView(store: store)
                    .preferredColorScheme(.dark)
            }
            .sheet(item: $store.scope(state: \.destination?.share, action: \.destination.share)) { store in
                ShareSheet(store: store)
            }
            .overlay {
                if store.showNewSongsTooltip {
                    FullScreenTooltipView(auraOverlayIcon: Image.Omniplayer.arrowRight,
                                          titleText: L10n.FeatureOmniPlayer.newSongsReady,
                                          subtitleText: L10n.FeatureOmniPlayer.swipeToNextClip,
                                          subtitleTextIcon: Image.Icon.nextTrack,
                                          buttonText: L10n.FeatureOmniPlayer.fullscreenCoverDismiss,
                                          action: { store.send(.dismissTooltip) })
                        .animation(.spring(response: 0.6, dampingFraction: 0.8), value: store.showNewSongsTooltip)
                }
            }
            .overlay(alignment: .top) {
                ExpandedPlayerCollapsibleHeader(store: store, verticalScrollPosition: $verticalScrollPosition)
                    .onTapGesture {
                        scrollToTopTrigger += 1
                    }
            }
            .toast($store.toast, position: .bottom, padding: EdgeInsets(bottom: 28), colorScheme: .dark)
            .onChange(of: store.scrollResetTrigger) { _, _ in
                scrollToTopTrigger += 1
                verticalScrollPosition = 0
            }
    }

    @ViewBuilder
    private var content: some View {
        MultiGestureContainerViewRepresentable(
            clips: store.player.queue.map { $0.clip },
            selectedIndex: $store.selectedItemIndex,
            content: VStack(spacing: 0) {
                // This is what floats above the song art before the user scrolls down.
                // It contains basic clip info (title, author, caption, and remixes),
                // playbar, and song actions.
                ExpandedPlayerChrome(
                    store: store,
                    verticalScrollPosition: $verticalScrollPosition,
                    onSeeMoreChevronTapped: {
                        scrollDownTrigger += 1
                        // Only track this once per clip
                        guard !store.didTapOrScrollToSeeMore else { return }
                        store.send(.didTapSeeMoreChevron)
                    }
                )
                ExpandedPlayerClipDetails(store: store, verticalScrollPosition: $verticalScrollPosition)
                    .offset(y: clipDetailsChromeOffset)
            }
            .ignoresSafeArea(edges: .top)
            .padding(.horizontal, 16)
            .background(Color.clear),
            verticalContentScrollOffset: { offset in
                Task { @MainActor in
                    verticalScrollPosition = max(0, offset)
                    // Check if we should show the controls, only if we're not already showing them
                    if store.shouldHideControls {
                        store.send(.didTapChromeToToggleControls(verticalOffset: verticalScrollPosition))
                    }
                }
            },
            isVerticalScrollingDisabled: shouldDisableVerticalScrolling,
            isScrubbing: store.player.isScrubbing,
            instantBlur: store.showNewSongsTooltip,
            dimGradient: store.shouldHideControls,
            verticalDragOffsetWhileAtTop: dragOffsetWhileAtTop,
            setVisibleHorizontalIndex: { store.send(.setSelectedIndex($0)) },
            playClipAtHorizontalIndex: { store.send(.internal(.playSelectedItem($0))) },
            scrollDownTrigger: scrollDownTrigger,
            scrollToTopTrigger: scrollToTopTrigger
        )
        .background(Material.regular)
        .clipShape(UnevenRoundedRectangle(
            topLeadingRadius: 12,
            bottomLeadingRadius: 0,
            bottomTrailingRadius: 0,
            topTrailingRadius: 12
        ))
        .environment(\.colorScheme, .dark)
        .sheet(item: $store.scope(state: \.destination?.songActions, action: \.destination.songActions)) { store in
            SongActionsMenu(store: store)
        }
        .sheet(item: $store.scope(state: \.destination?.attribution, action: \.destination.attribution)) { store in
            RemixOfSheet(store: store)
        }
        .sheet(item: $store.scope(state: \.destination?.remix, action: \.destination.remix)) { store in
            if FeatureFlag.legacy.remixV2 {
                RemixActionsSheetV2(store: store)
            } else {
                RemixActionsSheetRedesign(store: store)
            }
        }
    }
}
