import AnalyticsClient
import APIClient
import AVFoundation
import ComponentLibrary
import ComposableArchitecture
import FeatureClipDetail
import PlayerClient
import SwiftUI
import Utilities

@Reducer
public struct CompactPlayerV3 {
    @ObservableState
    public struct State: Equatable {
        @Shared public var player: OmniPlayerPlaybackState
        let autoStart: Bool
        var clip: Clip
        @Shared(.inMemory(.isPlayingKey)) var isPlaying: Bool = false

        public init(player: Shared<OmniPlayerPlaybackState>, autoStart: Bool, clip: Clip) {
            self._player = player
            self.autoStart = autoStart
            self.clip = clip
        }
    }

    public enum Action {
        case playTapped
        case pauseTapped
        case nextTapped

        case updateClip(Clip)

        case delegate(Delegate)

        public enum Delegate {
            case playTapped
            case pauseTapped
            case nextTapped
        }
    }

    public init() {}

    public var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .playTapped:
                return .send(.delegate(.playTapped))

            case .pauseTapped:
                return .send(.delegate(.pauseTapped))

            case .nextTapped:
                return .send(.delegate(.nextTapped))

            case .updateClip(let clip):
                state.clip = clip
                return .none

            case .delegate:
                // Catch-all
                return .none
            }
        }
    }
}

public struct CompactPlayerV3View: View {
    let store: StoreOf<CompactPlayerV3>

    // Refreshes the very first time the CompactPlayer opens up
    @State private var hasTriggeredMarqueeRefresh = false

    public init(store: StoreOf<CompactPlayerV3>) {
        self.store = store
    }

    private var clip: Clip {
        store.player.clip
    }

    public var body: some View {
        ZStack(alignment: .bottom) {
            HStack(spacing: 0) {
                RemoteImage(url: clip.largeImageUrl, fallbackId: clip.id.remoteId)
                    .aspectRatio(4 / 3, contentMode: .fill)
                    .frame(width: 36, height: 44)
                    .clipShape(RoundedRectangle(cornerRadius: 6))
                    .padding(.trailing, 8)

                VStack(spacing: 4) {
                    HStack(spacing: 0) {
                        VStack(alignment: .leading, spacing: 2) {
                            titleBar
                                .lineLimit(1)
                                .foregroundStyle(Color.SemanticV1.textPrimary)

                            authorBar
                                .lineLimit(1)
                                .foregroundStyle(Color.SemanticV1.textSecondary)
                                .blendMode(.luminosity)
                        }
                        .padding(.bottom, 2) // Visual offset to match designs

                        Spacer(minLength: 0)

                        playbackControls
                    }
                }
                .padding(.trailing, 4)
            }
            .padding(10)

            CompactPlayerProgressView(
                displayTime: store.player.displayTime.seconds,
                totalTime: store.player.totalTime.isInvalid ? store.player.fallbackTotalTimeSeconds : store.player.totalTime.seconds,
                isLoading: store.player.timeControlStatus == .waitingToPlayAtSpecifiedRate
            )
            .clipShape(Rectangle())
        }
        .background {
            RemoteImage(url: clip.largeImageUrl, fallbackId: clip.id.remoteId)
                .aspectRatio(4 / 3, contentMode: .fill)
                .frame(height: 100)
                .blur(radius: 24)
                .opacity(0.25)
        }
        .onAppear {
            // Force a refresh of the marquee text after a delay
            // This ensures the layout is complete before the marquee animation starts
            if !hasTriggeredMarqueeRefresh {
                hasTriggeredMarqueeRefresh = true
            }
        }
    }

    @ViewBuilder
    var titleBar: some View {
        MarqueeText(
            text: clip.title,
            font: TypographyV1.caption2.uiFont ?? .systemFont(ofSize: 14),
            leftFade: 4,
            rightFade: 4,
            startDelay: 1
        )
        .id("title-\(clip.id.remoteId)-\(hasTriggeredMarqueeRefresh)")
    }

    @ViewBuilder
    var authorBar: some View {
        MarqueeText(
            text: clip.displayName,
            font: TypographyV1.caption2.uiFont ?? .systemFont(ofSize: 14),
            leftFade: 4,
            rightFade: 4,
            startDelay: 1
        )
        .id("author-\(clip.id.remoteId)-\(hasTriggeredMarqueeRefresh)")
    }

    @ViewBuilder
    var playbackControls: some View {
        HStack(spacing: 16) {
            CompactPlayerPlayPauseButtonV2(
                playTapped: { store.send(.playTapped) },
                pauseTapped: { store.send(.pauseTapped) },
                timeControlStatus: store.player.timeControlStatus
            )
            Button {
                // Simply using `.disabled` would accidentally trigger opening the expanded player
                if !store.player.isAtEndOfQueue {
                    store.send(.nextTapped)
                }
            } label: {
                Image.Icon.nextTrack
                    .renderingMode(.template)
                    .resizable()
                    .frame(width: 24, height: 24)
                    .foregroundColor(.SemanticV1.iconPrimary)
            }
            .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9, minimumOpacity: 0.5))
            .padding(.trailing, 10)
            .opacity(store.player.isAtEndOfQueue ? 0.4 : 1)
        }
        .padding(.leading, 4) // Better overlay for marquee titles
    }
}

private extension CompactPlayerV3View {
    /*
         The progress bar that can be used in CompactPlayerV3.
         This doesn't need a PlayerReducer, so it doesn't
         support scrubbing.
     */
    struct CompactPlayerProgressView: View {
        let displayTime: Double
        let totalTime: Double
        let isLoading: Bool

        @State private var progressWidth: Double = 0.0

        init(
            displayTime: Double,
            totalTime: Double,
            isLoading: Bool
        ) {
            self.displayTime = displayTime
            self.totalTime = totalTime
            self.isLoading = isLoading
        }

        var body: some View {
            Group {
                let progress = min(totalTime, max(0, displayTime))

                ProgressView(value: progress, total: totalTime)
                    .progressViewStyle(LinearProgressViewStyle(tint: Color.SemanticV1.iconPrimary))
                    .background(Color.SemanticV2.backgroundSmokeThin)
                    .blendMode(.luminosity)
                    .onGeometryChange(for: CGSize.self) { proxy in proxy.size } action: {
                        progressWidth = $0.width
                    }
                    .placeholderShimmering(
                        isVisible: isLoading,
                        opacity: 0.75,
                        color: Color.white,
                        duration: 1.5
                    )
                    .frame(height: 2)
                    .padding(.bottom, 1)
            }
            .contentShape(.rect)
            .background(Material.regular)
        }
    }
}
