import SwiftUI

public struct WaveformView: View {
    private let barWidth: CGFloat
    private let barSpacing: CGFloat
    private let waveformSource: WaveformData
    private let samples: WaveformDataMap
    private let barHeightRatio: CGFloat
    private let lowOpacityFactor: CGFloat
    private let resampledValues: WaveformDataMap
    private let selectedRange: ClosedRange<TimeInterval>
    private let waveformWidthOverride: CGFloat?

    private static let minimumWaveformHeightRatio = 0.1

    @State private var size: CGSize = .zero

    public init(
        waveformSource: WaveformData,
        waveformWidthOverride: CGFloat? = nil,
        barWidth: CGFloat = 3.0,
        barHeightRatio: CGFloat = 0.65,
        barSpacing: CGFloat = 3.0,
        lowOpacityFactor: CGFloat = 0.2,
        selectedRange: ClosedRange<TimeInterval>,
        resampledValues: WaveformDataMap
    ) {
        self.waveformSource = waveformSource
        self.waveformWidthOverride = waveformWidthOverride
        self.samples = waveformSource.waveformDataMap
        self.barWidth = barWidth
        self.barSpacing = barSpacing
        self.barHeightRatio = barHeightRatio
        self.lowOpacityFactor = lowOpacityFactor
        self.selectedRange = selectedRange
        self.resampledValues = resampledValues
    }

    public var body: some View {
        LazyHStack(spacing: barSpacing) {
            ForEach(resampledValues.keys, id: \.self) { key in
                let height = max(resampledValues[key] ?? 0, Self.minimumWaveformHeightRatio) * size.height /** barHeightRatio */
                let opacity = selectedRange.contains(key) ? 1.0 : lowOpacityFactor
                Capsule(style: .circular)
                    .fill(.foreground.opacity(opacity))
                    .frame(width: barWidth, height: height)
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .geometryGroup() /// Prevents `LazyHStack` animation wonkiness
        .onGeometryChange(for: CGSize.self, of: \.size) { newSize in
            size = newSize
        }
    }
}
