//
//  TVPlayerControlsView.swift
//  Yattee
//
//  AVKit-style player controls overlay for tvOS with focus-based navigation.
//

#if os(tvOS)
import SwiftUI

/// AVKit-style player controls overlay for tvOS.
struct TVPlayerControlsView: View {
    @Environment(\.appEnvironment) private var appEnvironment
    let playerState: PlayerState?
    let playerService: PlayerService?
    @FocusState.Binding var focusedControl: TVPlayerFocusTarget?

    let onShowSettings: () -> Void
    let onShowQueue: () -> Void
    let onShowDetails: () -> Void
    let onShowComments: () -> Void
    let onShowDebug: () -> Void
    let onClose: () -> Void
    /// Called when the on-screen play/pause button is tapped. Parent routes
    /// through `handlePlayPause()` so visibility/auto-hide timer behave
    /// consistently with the Siri Remote's hardware Play/Pause button.
    let onTogglePlayPause: () -> Void
    /// Called when scrubbing state changes - parent should stop auto-hide timer when true
    var onScrubbingChanged: ((Bool) -> Void)?
    /// Pending target time for the bar's accumulating remote-seek flow (arrow
    /// presses while focused but not in SELECT scrub mode).
    var remoteSeekTime: TimeInterval? = nil
    /// Called when user presses left/right on the focused bar outside SELECT scrub.
    var onRemoteSeek: ((Bool) -> Void)? = nil
    /// Bumped by the parent to cancel any in-progress scrub without seeking
    /// (used when the Menu button is pressed while scrubbing).
    var cancelScrubTrigger: UUID? = nil

    /// Whether the Debug button should be visible (user-toggled in Developer settings).
    private var showDebugButton: Bool {
        appEnvironment?.settingsManager.showTVDebugButton ?? false
    }

    @State private var playNextTapCount = 0
    @State private var playPreviousTapCount = 0
    @State private var playPauseTapCount = 0

    private var isPlaying: Bool {
        playerState?.playbackState == .playing
    }

    private var isTransportDisabled: Bool {
        playerState?.isTransportDisabled ?? true
    }

    private var playPauseIcon: String {
        isPlaying ? "pause.fill" : "play.fill"
    }

    var body: some View {
        ZStack {
            // Gradient overlay for readability
            gradientOverlay

            VStack(spacing: 0) {
                // Top bar with title and channel
                topBar
                    .padding(.top, 60)
                    .padding(.horizontal, 88)

                Spacer()

                // Progress bar - its own focus section
                TVPlayerProgressBar(
                    currentTime: playerState?.currentTime ?? 0,
                    duration: playerState?.duration ?? 0,
                    bufferedTime: playerState?.bufferedTime ?? 0,
                    storyboard: playerState?.preferredStoryboard,
                    chapters: playerState?.chapters ?? [],
                    onSeek: { time in
                        Task {
                            await playerService?.seek(to: time)
                        }
                    },
                    onScrubbingChanged: onScrubbingChanged,
                    isLive: playerState?.isLive ?? false,
                    sponsorSegments: playerState?.sponsorSegments ?? [],
                    remoteSeekTime: remoteSeekTime,
                    onRemoteSeek: onRemoteSeek,
                    cancelScrubTrigger: cancelScrubTrigger
                )
                .focusSection()
                .padding(.horizontal, 88)
                .padding(.bottom, 20)
                // DEBUG: Uncomment to see focus section boundaries
                // .border(.green, width: 2)

                // Action buttons row - focus section for horizontal nav
                actionButtons
                    .focusSection()
                    .padding(.horizontal, 88)
                    .padding(.bottom, 60)
                    // DEBUG: Uncomment to see focus section boundaries
                    // .border(.red, width: 2)
            }
        }
    }

    // MARK: - Gradient Overlay

    private var gradientOverlay: some View {
        VStack(spacing: 0) {
            // Top gradient
            LinearGradient(
                colors: [.black.opacity(0.8), .black.opacity(0.4), .clear],
                startPoint: .top,
                endPoint: .bottom
            )
            .frame(height: 200)

            Spacer()

            // Bottom gradient
            LinearGradient(
                colors: [.clear, .black.opacity(0.4), .black.opacity(0.8)],
                startPoint: .top,
                endPoint: .bottom
            )
            .frame(height: 300)
        }
        .ignoresSafeArea()
    }

    // MARK: - Top Bar

    private var topBar: some View {
        HStack(alignment: .center, spacing: 20) {
            // Channel avatar
            if let video = playerState?.currentVideo {
                ChannelAvatarView(
                    author: video.author,
                    size: 80,
                    yatteeServerURL: yatteeServerURL,
                    source: video.id.source
                )
            }

            VStack(alignment: .leading, spacing: 8) {
                // Video title
                Text(playerState?.currentVideo?.title ?? "")
                    .font(.headline)
                    .fontWeight(.semibold)
                    .lineLimit(2)
                    .foregroundStyle(.white)

                // Channel name
                if let channelName = playerState?.currentVideo?.author.name {
                    Text(channelName)
                        .font(.subheadline)
                        .foregroundStyle(.white.opacity(0.7))
                }
            }

            Spacer()

            // Loading indicator
            if playerState?.playbackState == .loading || playerState?.playbackState == .buffering {
                ProgressView()
                    .progressViewStyle(.circular)
                    .scaleEffect(1.5)
                    .padding(.trailing, 8)
            }

            // Close button — stops playback and dismisses.
            // Menu button only hides the player (keeps background playback),
            // so an explicit Close is kept here, icon-only in the top bar.
            // When `tvOSMenuButtonClosesVideo` is enabled, the Menu button
            // takes over this role and the explicit button is hidden.
            if appEnvironment?.settingsManager.tvOSMenuButtonClosesVideo != true {
                Button {
                    onClose()
                } label: {
                    Image(systemName: "xmark")
                        .font(.system(size: 26, weight: .semibold))
                }
                .buttonStyle(TVCloseButtonStyle())
                .focused($focusedControl, equals: .closeButton)
                .accessibilityLabel(Text("player.controls.close"))
            }
        }
    }

    private var yatteeServerURL: URL? {
        appEnvironment?.instancesManager.yatteeServerInstances.first { $0.isEnabled }?.url
    }

    // MARK: - Action Buttons

    private var actionButtons: some View {
        HStack(spacing: 24) {
            // MARK: Left cluster — info / meta actions
            HStack(spacing: 24) {
                Button {
                    onShowSettings()
                } label: {
                    TVActionButtonLabel(
                        systemImage: "gearshape",
                        title: String(localized: "player.controls.settings")
                    )
                }
                .buttonStyle(TVActionButtonStyle())
                .focused($focusedControl, equals: .settingsButton)

                Button {
                    onShowDetails()
                } label: {
                    TVActionButtonLabel(
                        systemImage: "info.circle",
                        title: String(localized: "player.controls.info")
                    )
                }
                .buttonStyle(TVActionButtonStyle())
                .focused($focusedControl, equals: .infoButton)

                if playerState?.currentVideo?.supportsComments == true {
                    Button {
                        onShowComments()
                    } label: {
                        TVActionButtonLabel(
                            systemImage: "bubble.left.and.bubble.right",
                            title: String(localized: "player.controls.comments")
                        )
                    }
                    .buttonStyle(TVActionButtonStyle())
                    .focused($focusedControl, equals: .commentsButton)
                }

                if showDebugButton {
                    Button {
                        onShowDebug()
                    } label: {
                        TVActionButtonLabel(
                            systemImage: "ant.circle",
                            title: String(localized: "player.debug.titleShort")
                        )
                    }
                    .buttonStyle(TVActionButtonStyle())
                    .focused($focusedControl, equals: .debugButton)
                }

                Spacer(minLength: 0)
            }
            .frame(maxWidth: .infinity, alignment: .leading)

            // MARK: Center cluster — transport (circular, icon-only)
            HStack(spacing: 20) {
                // Previous is always rendered so Play/Next stay in a fixed
                // position; disabled + dimmed when unavailable.
                let hasPrevious = playerState?.hasPrevious == true
                Button {
                    playPreviousTapCount += 1
                    Task { await playerService?.playPrevious() }
                } label: {
                    Image(systemName: "backward.fill")
                        .font(.system(size: 26, weight: .semibold))
                        .symbolEffect(.bounce.down.byLayer, options: .nonRepeating, value: playPreviousTapCount)
                }
                .buttonStyle(TVTransportButtonStyle())
                .focused($focusedControl, equals: .playPrevious)
                .disabled(!hasPrevious)
                .opacity(hasPrevious ? 1.0 : 0.3)
                .accessibilityLabel(Text("player.previous"))

                Button {
                    playPauseTapCount += 1
                    onTogglePlayPause()
                } label: {
                    Image(systemName: playPauseIcon)
                        .font(.system(size: 32, weight: .semibold))
                        .contentTransition(.symbolEffect(.replace, options: .speed(2)))
                        .symbolEffect(.bounce.down.byLayer, options: .nonRepeating, value: playPauseTapCount)
                }
                .buttonStyle(TVTransportButtonStyle(isPrimary: true))
                .focused($focusedControl, equals: .playPauseButton)
                .disabled(isTransportDisabled)
                .opacity(isTransportDisabled ? 0.3 : 1.0)
                .accessibilityLabel(Text(isPlaying ? "player.controls.pause" : "player.controls.play"))

                let hasNext = playerState?.hasNext == true
                Button {
                    playNextTapCount += 1
                    Task { await playerService?.playNext() }
                } label: {
                    Image(systemName: "forward.fill")
                        .font(.system(size: 26, weight: .semibold))
                        .symbolEffect(.bounce.down.byLayer, options: .nonRepeating, value: playNextTapCount)
                }
                .buttonStyle(TVTransportButtonStyle())
                .focused($focusedControl, equals: .playNext)
                .disabled(!hasNext)
                .opacity(hasNext ? 1.0 : 0.3)
                .accessibilityLabel(Text("player.next"))
            }

            // MARK: Right cluster — queue
            HStack(spacing: 24) {
                Spacer(minLength: 0)

                if let state = playerState, state.hasNext {
                    Button {
                        onShowQueue()
                    } label: {
                        TVActionButtonLabel(
                            systemImage: "list.bullet",
                            title: String(localized: "queue.section.count \(state.queue.count)")
                        )
                    }
                    .buttonStyle(TVActionButtonStyle())
                    .focused($focusedControl, equals: .queueButton)
                }
            }
            .frame(maxWidth: .infinity, alignment: .trailing)
        }
    }
}

// MARK: - Button Label

/// Shared label for action buttons: icon always visible, title only on focus.
private struct TVActionButtonLabel: View {
    let systemImage: String
    let title: String
    var symbolEffectTrigger: Int = 0

    var body: some View {
        VStack(spacing: 6) {
            Image(systemName: systemImage)
                .font(.system(size: 28))
                .symbolEffect(.bounce.down.byLayer, options: .nonRepeating, value: symbolEffectTrigger)
            Text(title)
                .font(.caption)
        }
    }
}

// MARK: - Button Styles

/// Button style for action buttons (settings, info, transport, queue).
/// Width is adaptive so localized labels fit when revealed on focus.
struct TVActionButtonStyle: ButtonStyle {
    @Environment(\.isFocused) private var isFocused

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundStyle(isFocused ? Color.black : .white)
            .lineLimit(1)
            .minimumScaleFactor(0.8)
            .padding(.horizontal, 20)
            .frame(minWidth: 100, minHeight: 80)
            .glassBackground(
                isFocused ? .tinted(.white.opacity(0.35)) : .regular,
                in: .rect(cornerRadius: 12),
                fallback: isFocused ? .ultraThickMaterial : .ultraThinMaterial,
                colorScheme: .light
            )
            .scaleEffect(configuration.isPressed ? 0.95 : (isFocused ? 1.05 : 1.0))
            .animation(.easeInOut(duration: 0.15), value: isFocused)
            .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
    }
}

/// Circular icon-only button style for transport controls (previous / play-pause / next).
/// Primary variant is larger and uses a filled white background when focused.
struct TVTransportButtonStyle: ButtonStyle {
    @Environment(\.isFocused) private var isFocused
    var isPrimary: Bool = false

    func makeBody(configuration: Configuration) -> some View {
        let size: CGFloat = isPrimary ? 88 : 72
        let style: GlassStyle = isFocused ? .tinted(.white.opacity(0.35)) : .regular
        let fallback: GlassFallbackMaterial = isFocused ? .ultraThickMaterial : .ultraThinMaterial
        return configuration.label
            .frame(width: size, height: size)
            .glassBackground(style, in: .circle, fallback: fallback, colorScheme: .light)
            .foregroundStyle(isFocused ? Color.black : .white)
            .scaleEffect(configuration.isPressed ? 0.92 : (isFocused ? 1.08 : 1.0))
            .animation(.easeInOut(duration: 0.15), value: isFocused)
            .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
    }
}

/// Compact circular button style for the top-right close affordance.
struct TVCloseButtonStyle: ButtonStyle {
    @Environment(\.isFocused) private var isFocused

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundStyle(isFocused ? Color.black : .white)
            .frame(width: 64, height: 64)
            .glassBackground(
                isFocused ? .tinted(.white.opacity(0.35)) : .regular,
                in: .circle,
                fallback: isFocused ? .ultraThickMaterial : .ultraThinMaterial,
                colorScheme: .light
            )
            .scaleEffect(configuration.isPressed ? 0.92 : (isFocused ? 1.08 : 1.0))
            .animation(.easeInOut(duration: 0.15), value: isFocused)
            .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
    }
}

#endif
