import ComposableArchitecture
import SwiftUI

public struct WaveformShape: Shape {
    let waveformData: [Float]
    let width: CGFloat
    let height: CGFloat
    let isFineScrubbing: Bool
    let clipDuration: Double
    let isPlaybackActive: Bool
    let windowSizeRatioWhenFineScrubbing: CGFloat
    let windowSizeRatioWhenPlaybackActive: CGFloat
    let stepX: CGFloat
    let xOffset: CGFloat

    public init(store: StoreOf<WaveformEditor>) {
        self.waveformData = store.waveformStripShapeData
        self.width = store.waveformStripWidth
        self.height = store.waveformStripHeight
        self.isFineScrubbing = store.isFineScrubbing
        self.clipDuration = store.clipDuration
        self.isPlaybackActive = store.playbackState.isActive
        self.windowSizeRatioWhenFineScrubbing = store.windowSizeRatioWhenFineScrubbing
        self.windowSizeRatioWhenPlaybackActive = store.windowSizeRatioWhenPlaybackActive
        self.stepX = store.waveformStripShapeStepSize
        self.xOffset = store.waveformStripShapeHorizontalOffset
    }

    public func path(in _: CGRect) -> Path {
        Path { path in
            guard !waveformData.isEmpty else { return }

            let maxAmplitude = waveformData.map(abs).max() ?? 1.0
            let midY = height / 2
            path.move(to: CGPoint(x: 0, y: midY))

            for i in 0 ..< waveformData.count {
                let x = CGFloat(i) * stepX
                let normalizedAmplitude = CGFloat(waveformData[i]) / CGFloat(maxAmplitude)
                let y = midY - (normalizedAmplitude * height * 0.4)
                path.addLine(to: CGPoint(x: x, y: y))
            }

            let lastX = CGFloat(waveformData.count - 1) * stepX
            path.addLine(to: CGPoint(x: lastX, y: midY))

            for i in (0 ..< waveformData.count).reversed() {
                let x = CGFloat(i) * stepX
                let normalizedAmplitude = CGFloat(waveformData[i]) / CGFloat(maxAmplitude)
                let y = midY + (normalizedAmplitude * height * 0.4)
                path.addLine(to: CGPoint(x: x, y: y))
            }

            path.closeSubpath()
        }
        .offsetBy(
            dx: xOffset,
            dy: 0
        )
    }
}
