//
//  BarStyleWaveformView.swift
//  vibes
//
//  Bar-style waveform visualization for Versions exploration
//

import SwiftUI

struct BarStyleWaveformView: View {
    let isAnimating: Bool
    let progress: Double
    let waveformSeed: Double
    let playbackProgress: Double
    let waveAmplitude: Double  // Discrete value for wave strength

    @State private var frozenPhase: Double = 0
    @State private var lastAnimatingState: Bool = false

    private let barCount: Int = 60
    private let barSpacing: CGFloat = 3

    var body: some View {
        GeometryReader { geometry in
            TimelineView(.animation(minimumInterval: 1/60, paused: false)) { timeline in
                Canvas { context, size in
                    let currentTime = timeline.date.timeIntervalSinceReferenceDate

                    // Capture phase at the exact moment we stop animating
                    let basePhase: Double
                    if isAnimating {
                        basePhase = currentTime
                        DispatchQueue.main.async {
                            frozenPhase = currentTime
                            lastAnimatingState = true
                        }
                    } else {
                        basePhase = frozenPhase
                        if lastAnimatingState {
                            DispatchQueue.main.async {
                                lastAnimatingState = false
                            }
                        }
                    }

                    drawBars(context: context, size: size, phase: basePhase, progress: progress)
                }
            }
            .blur(radius: max(0, (1.0 - progress / 0.8)) * 8.0)  // Unblur completes at 80%
        }
    }

    private func drawBars(context: GraphicsContext, size: CGSize, phase: Double, progress: Double) {
        let totalBarWidth = size.width / CGFloat(barCount)
        let barWidth = totalBarWidth - barSpacing

        for i in 0..<barCount {
            let x = CGFloat(i) * totalBarWidth + barSpacing / 2
            let normalizedX = Double(i) / Double(barCount - 1)

            // Calculate bar height based on waveform seed
            let barHeight = calculateBarHeight(
                index: i,
                normalizedX: normalizedX,
                maxHeight: size.height,
                phase: phase,
                progress: progress
            )

            // Cascading scale-up loading animation
            let barDelay = normalizedX * 0.3  // Stagger based on position (left to right)
            let adjustedProgress = max(0, min(1.0, (progress - barDelay) / (1.0 - barDelay)))

            // Scale up from bottom with easing
            let scaleProgress = adjustedProgress * adjustedProgress * (3.0 - 2.0 * adjustedProgress)  // Smoothstep

            // Apply scale to bar height (bars grow from bottom)
            let visibleHeight = barHeight * scaleProgress

            // Calculate fill ratio for smooth playback progress
            let barWidthNormalized = 1.0 / Double(barCount)
            let fillRatio: Double

            if normalizedX + barWidthNormalized < playbackProgress {
                // Bar is fully behind playback position
                fillRatio = 1.0
            } else if normalizedX > playbackProgress {
                // Bar is fully ahead of playback position
                fillRatio = 0.0
            } else {
                // Bar is at the playback position - partially filled
                fillRatio = (playbackProgress - normalizedX) / barWidthNormalized
            }

            // Draw bar centered vertically
            let barY = (size.height - visibleHeight) / 2

            // Draw gray portion (unplayed) - right side
            if fillRatio < 1.0 {
                let grayWidth = barWidth * (1.0 - fillRatio)
                let grayX = x + (barWidth * fillRatio)
                let grayRect = CGRect(
                    x: grayX,
                    y: barY,
                    width: grayWidth,
                    height: visibleHeight
                )
                let grayRoundedRect = RoundedRectangle(cornerRadius: barWidth / 2)
                    .path(in: grayRect)
                context.fill(
                    grayRoundedRect,
                    with: .color(Constants.Colors.Foreground.tertiary.opacity(scaleProgress * 0.5))
                )
            }

            // Draw orange portion (played) - left side
            if fillRatio > 0.0 {
                let orangeWidth = barWidth * fillRatio
                let orangeRect = CGRect(
                    x: x,
                    y: barY,
                    width: orangeWidth,
                    height: visibleHeight
                )
                let orangeRoundedRect = RoundedRectangle(cornerRadius: barWidth / 2)
                    .path(in: orangeRect)
                context.fill(
                    orangeRoundedRect,
                    with: .color(Constants.Colors.Accent.orange.opacity(scaleProgress * 1.0))
                )
            }
        }
    }

    private func calculateBarHeight(index: Int, normalizedX: Double, maxHeight: CGFloat, phase: Double, progress: Double) -> CGFloat {
        // Use seed to create consistent randomness per bar
        let seedModifier = waveformSeed.truncatingRemainder(dividingBy: 1000.0) / 1000.0

        // Create pseudo-random value for this bar (consistent based on index and seed)
        let barSeed = sin(Double(index) * 12.9898 + seedModifier * 78.233) * 43758.5453
        let randomValue = barSeed - floor(barSeed)  // Get fractional part [0, 1]

        // Most bars should be around medium height (square-like)
        let baseHeight = 0.65  // Base height ratio (most bars around 65%)

        // Add moderate variation for peaks and valleys
        let variation = (randomValue - 0.5) * 0.5  // Range: -0.25 to +0.25

        // Occasional peaks (10% chance of being taller)
        let isPeak = randomValue > 0.9
        let peakBoost = isPeak ? 0.3 : 0.0

        // Occasional valleys (10% chance of being shorter)
        let isValley = randomValue < 0.1
        let valleyReduction = isValley ? -0.25 : 0.0

        // Combine for final height ratio
        var heightRatio = baseHeight + variation + peakBoost + valleyReduction

        // Add wave animation using discrete amplitude parameter
        if isAnimating {
            let wave = sin(phase * 2.5 + Double(index) * 0.15)
            heightRatio += wave * waveAmplitude
        }

        let clampedRatio = max(0.2, min(1.0, heightRatio))  // Clamp between 20% and 100%

        // Calculate final height
        let minHeight = maxHeight * 0.04
        let heightRange = maxHeight * 0.25

        return minHeight + (CGFloat(clampedRatio) * heightRange)
    }

    private func getAudioEnvelope(normalizedX: Double, seedOffset: Double) -> Double {
        // Normalized envelope with less dramatic variations
        let chorusBoost = 0.85 + (seedOffset * 0.15)  // Reduced from 0.8 + 0.4

        if normalizedX < 0.15 {
            return 0.55 + (normalizedX / 0.15) * 0.2  // Starts higher, less buildup
        } else if normalizedX < 0.30 {
            return 0.70 + (seedOffset * 0.1)  // Compressed range
        } else if normalizedX < 0.35 {
            return (0.70 + (seedOffset * 0.1)) + ((normalizedX - 0.30) / 0.05) * 0.2  // Smoother transition
        } else if normalizedX < 0.50 {
            return chorusBoost
        } else if normalizedX < 0.65 {
            return 0.65 + (seedOffset * 0.1)  // Less variation
        } else if normalizedX < 0.75 {
            return (0.65 + (seedOffset * 0.1)) + ((normalizedX - 0.65) / 0.10) * 0.25  // Gentler buildup
        } else if normalizedX < 0.90 {
            return chorusBoost
        } else {
            return chorusBoost - ((normalizedX - 0.90) / 0.10) * 0.3  // Gentler fadeout
        }
    }
}

#Preview {
    BarStyleWaveformView(isAnimating: false, progress: 1.0, waveformSeed: 42.0, playbackProgress: 0.5, waveAmplitude: 0.08)
        .frame(height: 300)
        .background(Constants.Colors.Background.primary)
}
