import SwiftUI

/// Half-sheet EQ panel with three vertical sliders, preset picker, and reset button.
struct EQView: View {
    @Environment(PlayerViewModel.self) private var playerVM
    @EnvironmentObject private var theme: AppTheme

    var body: some View {
        @Bindable var vm = playerVM

        VStack(spacing: 24) {
            // Header: title + preset picker
            HStack {
                Text("Equalizer")
                    .font(.title3.bold())
                    .foregroundStyle(theme.primaryText)

                Spacer()

                Menu {
                    ForEach(EQPreset.allCases.filter { $0 != .custom }) { preset in
                        Button {
                            playerVM.applyEQPreset(preset)
                        } label: {
                            HStack {
                                Text(preset.displayName)
                                if playerVM.eqPreset == preset {
                                    Image(systemName: "checkmark")
                                }
                            }
                        }
                    }
                } label: {
                    HStack(spacing: 4) {
                        Text(playerVM.eqPreset.displayName)
                            .font(.subheadline.weight(.medium))
                        Image(systemName: "chevron.up.chevron.down")
                            .font(.caption2)
                    }
                    .foregroundStyle(theme.accent)
                }
                .accessibilityIdentifier("eqPresetPicker")
            }
            .padding(.horizontal, 24)

            // Three vertical sliders side by side
            HStack(spacing: 0) {
                VerticalEQSlider(
                    label: "LOW",
                    value: $vm.eqLow,
                    onChange: { playerVM.setEQ(low: playerVM.eqLow, mid: playerVM.eqMid, high: playerVM.eqHigh) }
                )

                VerticalEQSlider(
                    label: "MID",
                    value: $vm.eqMid,
                    onChange: { playerVM.setEQ(low: playerVM.eqLow, mid: playerVM.eqMid, high: playerVM.eqHigh) }
                )

                VerticalEQSlider(
                    label: "HIGH",
                    value: $vm.eqHigh,
                    onChange: { playerVM.setEQ(low: playerVM.eqLow, mid: playerVM.eqMid, high: playerVM.eqHigh) }
                )
            }
            .padding(.horizontal, 16)

            // Reset button
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    playerVM.resetEQ()
                }
            } label: {
                Text("Reset")
                    .font(.subheadline.weight(.medium))
                    .foregroundStyle(playerVM.isEQActive ? theme.accent : theme.secondaryText)
                    .padding(.horizontal, 20)
                    .padding(.vertical, 8)
                    .background(
                        RoundedRectangle(cornerRadius: 8)
                            .fill(theme.secondaryBackground)
                    )
            }
            .disabled(!playerVM.isEQActive)
            .accessibilityIdentifier("eqResetButton")

            Spacer()
        }
        .padding(.top, 20)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(theme.secondaryBackground)
        .presentationDetents([.medium])
        .presentationDragIndicator(.visible)
    }
}

// MARK: - Vertical EQ Slider

/// Custom vertical slider for a single EQ band.
/// Range: -24 to +12 dB with visual center line at 0 dB.
/// Features: dB readout, haptic at 0 dB crossing, double-tap reset.
private struct VerticalEQSlider: View {
    let label: String
    @Binding var value: Float
    let onChange: () -> Void

    @EnvironmentObject private var theme: AppTheme
    @State private var lastHapticSide: HapticSide = .center

    private enum HapticSide { case negative, center, positive }

    private static let minDB: Float = -24
    private static let maxDB: Float = 12
    private static let range: Float = maxDB - minDB  // 36

    var body: some View {
        VStack(spacing: 8) {
            // dB readout
            Text(formatGain(value))
                .font(.system(.caption, design: .monospaced))
                .foregroundStyle(theme.primaryText)
                .frame(height: 16)

            // Slider track
            GeometryReader { geo in
                let height = geo.size.height
                let centerY = height * CGFloat(Self.maxDB / Self.range) // 0 dB position from top
                let thumbY = height * CGFloat((Self.maxDB - value) / Self.range)

                ZStack(alignment: .top) {
                    // Track background
                    RoundedRectangle(cornerRadius: 3)
                        .fill(theme.seekbarBackground)
                        .frame(width: 6)
                        .frame(maxHeight: .infinity)

                    // Center line at 0 dB
                    Rectangle()
                        .fill(theme.separatorColor)
                        .frame(width: 24, height: 1)
                        .offset(y: centerY)

                    // Fill from center to thumb
                    let fillStart = min(centerY, thumbY)
                    let fillHeight = abs(thumbY - centerY)
                    RoundedRectangle(cornerRadius: 3)
                        .fill(theme.accent)
                        .frame(width: 6, height: fillHeight)
                        .offset(y: fillStart)

                    // Thumb indicator
                    Circle()
                        .fill(theme.accent)
                        .frame(width: 20, height: 20)
                        .shadow(color: .black.opacity(0.3), radius: 2, y: 1)
                        .offset(y: thumbY - 10)
                }
                .frame(maxWidth: .infinity)
                .contentShape(Rectangle())
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .onChanged { drag in
                            let fraction = Float(drag.location.y / height)
                            let newValue = Self.maxDB - fraction * Self.range
                            let clamped = min(Self.maxDB, max(Self.minDB, newValue))
                            value = clamped
                            checkHaptic(clamped)
                            onChange()
                        }
                )
                .onTapGesture(count: 2) {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        value = 0
                    }
                    lastHapticSide = .center
                    onChange()
                }
            }

            // Band label
            Text(label)
                .font(.caption.weight(.semibold))
                .foregroundStyle(theme.secondaryText)
        }
        .frame(maxWidth: .infinity)
        .onAppear {
            lastHapticSide = value > 0 ? .positive : value < 0 ? .negative : .center
        }
    }

    private func formatGain(_ db: Float) -> String {
        if db == 0 { return "0 dB" }
        let sign = db > 0 ? "+" : ""
        // Show integer if whole number, otherwise one decimal
        if db == db.rounded() {
            return "\(sign)\(Int(db)) dB"
        }
        return "\(sign)\(String(format: "%.1f", db)) dB"
    }

    /// Fire haptic when crossing the 0 dB center line.
    private func checkHaptic(_ newValue: Float) {
        let newSide: HapticSide = newValue > 0.5 ? .positive : newValue < -0.5 ? .negative : .center
        let crossed = (lastHapticSide == .positive && newSide == .negative) ||
                      (lastHapticSide == .negative && newSide == .positive) ||
                      (lastHapticSide != .center && newSide == .center)
        if crossed {
            UIImpactFeedbackGenerator(style: .light).impactOccurred()
        }
        lastHapticSide = newSide
    }
}
