import Localization
import Popovers
import SwiftUI

public struct SliderRow: View {
    let title: String
    let infoPopoverText: String
    var isToggle: Bool = false
    @Binding var sliderValue: Double
    var warningThreshold: Double?
    let playHaptics: Bool

    // Percent
    @State var amount = 0.25
    @State var isDragging = false
    @State var infoPopoverIsPresented = false

    /// Only show up to 3 digits
    let maxDigits = 3
    private func limitedBinding(_ binding: Binding<Double>) -> Binding<Double> {
        Binding(
            get: { binding.wrappedValue },
            set: { newValue in
                // Clamp to whole percentages
                let displayValue = round(newValue * 100)
                binding.wrappedValue = displayValue / 100
            }
        )
    }

    private let sliderWidth = 114

    public init(
        title: String,
        infoPopoverText: String,
        isToggle: Bool = false,
        sliderValue: Binding<Double> = .constant(0.0),
        warningThreshold: Double? = nil,
        playHaptics: Bool = true
    ) {
        self.title = title
        self.infoPopoverText = infoPopoverText
        self.isToggle = isToggle
        self._sliderValue = sliderValue
        self.warningThreshold = warningThreshold
        self.playHaptics = playHaptics
    }

    public var body: some View {
        HStack(spacing: 0) {
            Text(title)
                .typographyV1(.subtitleXsmall)
                .foregroundStyle(Color.SemanticV2.foregroundPrimary)
                .lineLimit(1)
                .padding(.trailing, 6)

            /// Info Button
            Button {
                infoPopoverIsPresented = true
            } label: {
                Image.Icon.informationThick
                    .resizable()
                    .frame(width: 16, height: 16)
                    .foregroundStyle(Color.SemanticV2.foregroundInactive)
            }
            .popover(
                present: $infoPopoverIsPresented,
                attributes: {
                    $0.position = .absolute(originAnchor: .top, popoverAnchor: .bottom)
                    $0.presentation.animation = .snappy.speed(2)
                    $0.dismissal.animation = .snappy.speed(2)
                }
            ) {
                SimpleTooltipView(text: infoPopoverText)
            }

            Spacer()

            /// Custom Slider
            CustomSlider(value: limitedBinding($sliderValue), isDragging: $isDragging)
                .frame(width: 114, height: 24) // Fixed width value on this custom slider for now
                .padding(.horizontal, 24)

            /// Percent TextField
            TextField("", value: limitedBinding($sliderValue), format: .percent.precision(.fractionLength(0)))
                .keyboardType(.numberPad)
                .typographyV1(.subtitleXsmall)
                .foregroundStyle(percentTextfieldColor)
                .disabled(true) // TODO: Make this text field editable in a followup
                .multilineTextAlignment(.trailing)
                .frame(width: 40) // Fixed width for this text field
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
        .background(Color.SemanticV2.backgroundPrimary)
        .cornerRadius(8)
        .modifier(if: playHaptics) {
            $0
                .sensoryFeedbackIfEnabled(.selection, trigger: isDragging)
                .sensoryFeedbackIfEnabled(.selection, trigger: limitedBinding($sliderValue).wrappedValue)
        }
    }

    var percentTextfieldColor: Color {
        if let warningThreshold, sliderValue > warningThreshold {
            return Color.SemanticV2.accentError
        } else {
            return Color.SemanticV2.foregroundPrimary
        }
    }
}

public struct CustomSlider: View {
    @Binding var value: Double
    @Binding private var isDragging: Bool

    /// Layout
    @State private var width: CGFloat = 0
    @State private var height: CGFloat = 0
    @State private var thumbWidth: CGFloat = 0
    @State private var notchWidth: CGFloat = 0
    @State private var notchSpacing: CGFloat = 0
    @State private var numberOfNotches: Int = 0

    var clampedThumbPosition: CGPoint {
        CGPoint(
            x: min(max(width * CGFloat(value) + thumbWidth / 2, thumbWidth / 2), width - (thumbWidth / 2)),
            y: height / 2
        )
    }

    var thumbXOffset: CGFloat {
        let modifier = value - 0.5
        return max(width - thumbWidth, 0) * modifier
    }

    @State var xOffset: CGFloat = 0

    public init(value: Binding<Double>, isDragging: Binding<Bool> = .constant(false)) {
        self._value = value
        self._isDragging = isDragging
    }

    private let thumbAspectRatio: CGFloat = 10 / 24 // 10:24 ratio for the thumb
    private let notchAspectRatio: CGFloat = 2 / 24 // 2:24 ratio for the notch
    private let notchSpacingAspectRatio: CGFloat = 9.2 / 24 // 9.2:24 ratio for the notch spacing

    public var body: some View {
        ZStack {
            // Notch View
            HStack {
                ForEach(0 ..< numberOfNotches, id: \.self) { _ in
                    RoundedRectangle(cornerRadius: .infinity)
                        .fill(Color.SemanticV2.foregroundPrimary)
                        .frame(width: notchWidth)
                }
            }
            .mask {
                LinearGradient(
                    stops: [
                        .init(color: .black.opacity(0.05), location: 0),
                        .init(color: .black.opacity(0.05), location: 0.3),
                        .init(color: .black.opacity(0.20), location: 0.4),
                        .init(color: .black.opacity(0.40), location: 0.5),
                        .init(color: .black.opacity(0.20), location: 0.6),
                        .init(color: .black.opacity(0.05), location: 0.7),
                        .init(color: .black.opacity(0.05), location: 1),
                    ],
                    startPoint: .leading,
                    endPoint: .trailing
                )
                .frame(width: width * 2, height: height)
                .offset(x: thumbXOffset)
            }

            // Thumb
            RoundedRectangle(cornerRadius: .infinity)
                .fill(Color.SemanticV2.accentBrand)
                .frame(width: thumbWidth, height: height)
                .offset(x: thumbXOffset)
                .animation(.easeInOut(duration: 0.1), value: isDragging)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .onGeometryChange(for: CGSize.self) { proxy in proxy.size } action: { size in
            width = size.width
            height = size.height
            thumbWidth = height * thumbAspectRatio
            notchWidth = height * notchAspectRatio
            notchSpacing = height * notchSpacingAspectRatio + (notchWidth / 2)
            /// Calculate the number of notches based on the width of the slider
            let numberOfNotchesOnEachSideFloat: CGFloat = (size.width - notchWidth) / notchSpacing / 2
            var numberOfNotchesOnEachSide: Int
            if numberOfNotchesOnEachSideFloat.isNaN || numberOfNotchesOnEachSideFloat.isInfinite || numberOfNotchesOnEachSideFloat < 0 {
                numberOfNotchesOnEachSide = 0
            } else {
                numberOfNotchesOnEachSide = Int(numberOfNotchesOnEachSideFloat)
            }
            numberOfNotches = numberOfNotchesOnEachSide * 2 + 1
        }
        .gesture(
            DragGesture(minimumDistance: 0)
                .onChanged { gesture in
                    isDragging = true
                    let newValue = Double(gesture.location.x / width)
                    value = min(max(newValue, 0.0), 1.0)

                    let modifier = value - 0.5
                    xOffset = max(width - thumbWidth, 0) * modifier
                }
                .onEnded { _ in
                    isDragging = false

                    let modifier = value - 0.5
                    xOffset = max(width - thumbWidth, 0) * modifier
                }
        )
    }
}

struct SimpleTooltipView: View {
    enum Style {
        case info // For sliders/info popovers
        case timestamp // For waveform timecode tooltips
    }
    
    let text: String
    let style: Style
    
    init(text: String, style: Style = .info) {
        self.text = text
        self.style = style
    }
    
    @ViewBuilder
    var body: some View {
        if style == .timestamp {
            Text(text)
                .figmaMCPTypography(TypographyV1.FigmaMCP.timecode.inputSans())
                .foregroundColor(Color.FigmaMCP.Semantic.foregroundPrimary)
                .tracking(0.24)
                .lineLimit(1)
                .padding(.horizontal, 12)
                .padding(.vertical, 8)
                .background(
                    RoundedRectangle(cornerRadius: 8)
                        .fill(Color.FigmaMCP.Semantic.fogThin)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8))
                )
        } else {
            Text(text)
                .figmaMCPTypography(TypographyV1.FigmaMCP.xSmallRegular)
                .foregroundColor(Color.FigmaMCP.Semantic.foregroundPrimary)
                .tracking(0.24)
                .lineLimit(1)
                .padding(.horizontal, 12)
                .padding(.vertical, 12)
                .background(
                    RoundedRectangle(cornerRadius: 8)
                        .fill(Color.FigmaMCP.Semantic.fogThin)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8))
                )
        }
    }
}

// A UIViewRepresentable that uses UIVisualEffectView with only blur, no vibrancy
struct BackdropBlurView: UIViewRepresentable {
    var radius: CGFloat

    func makeUIView(context _: Context) -> UIVisualEffectView {
        // Create a blur effect without any vibrancy or color shifting
        let view = UIVisualEffectView(effect: UIBlurEffect(style: .regular))

        // Remove the default subtle overlay tint that UIVisualEffectView adds
        view.backgroundColor = .clear

        // Disable vibrancy effect that might alter colors
        view.contentView.backgroundColor = .clear

        return view
    }

    func updateUIView(_ uiView: UIVisualEffectView, context _: Context) {
        // You can dynamically update the blur radius by adjusting alpha
        // (Unfortunately UIBlurEffect doesn't let you set radius directly)
        uiView.alpha = min(1.0, radius * 0.0333)
    }
}
