import AVFoundation
import Combine
import ComposableArchitecture
import CoreHaptics
import SwiftUI

public struct WaveformSelector: View {
    let start: Double
    let end: Double
    let totalWidth: Double
    let height: Double
    let duration: Double
    let minimumDuration: Double? = nil
    let maximumDuration: Double? = nil
    let onLeftHandleDrag: (Double) -> Void
    let onRightHandleDrag: (Double) -> Void
    let onLeftHandleDragEnd: (Double) -> Void
    let onRightHandleDragEnd: (Double) -> Void
    let canMoveLeftHandle: Bool
    let canMoveRightHandle: Bool
    let isLeftHandleHidden: Bool
    let isRightHandleHidden: Bool
    let onFineScrub: () -> Void
    let onFineScrubEnd: () -> Void
    let leftHandleMinPosition: Double?
    let leftHandleMaxPosition: Double?
    let rightHandleMinPosition: Double?
    let rightHandleMaxPosition: Double?
    let fineScrubbingDisabled: Bool
    let onFineScrubAndDragStartLeft: () -> Void
    let onFineScrubAndDragStartRight: () -> Void
    let onFineScrubAndDragEnd: () -> Void
    let playbackState: WaveformEditor.PlaybackState
    @State private var currentStart: Double
    @State private var currentEnd: Double

    public init(
        start: Double,
        end: Double,
        totalWidth: Double,
        height: Double,
        duration: Double,
        onLeftHandleDrag: @escaping (Double) -> Void,
        onRightHandleDrag: @escaping (Double) -> Void,
        onLeftHandleDragEnd: @escaping (Double) -> Void,
        onRightHandleDragEnd: @escaping (Double) -> Void,
        canMoveLeftHandle: Bool,
        canMoveRightHandle: Bool,
        isLeftHandleHidden: Bool,
        isRightHandleHidden: Bool,
        onFineScrub: @escaping () -> Void,
        onFineScrubEnd: @escaping () -> Void,
        leftHandleMinPosition: Double? = nil,
        leftHandleMaxPosition: Double? = nil,
        rightHandleMinPosition: Double? = nil,
        rightHandleMaxPosition: Double? = nil,
        fineScrubbingDisabled: Bool = false,
        onFineScrubAndDragStartLeft: @escaping () -> Void,
        onFineScrubAndDragStartRight: @escaping () -> Void,
        onFineScrubAndDragEnd: @escaping () -> Void,
        playbackState: WaveformEditor.PlaybackState
    ) {
        self.start = start
        self.end = end
        self.totalWidth = totalWidth
        self.height = height
        self.duration = duration
        self.onLeftHandleDrag = onLeftHandleDrag
        self.onRightHandleDrag = onRightHandleDrag
        self.onLeftHandleDragEnd = onLeftHandleDragEnd
        self.onRightHandleDragEnd = onRightHandleDragEnd
        self.canMoveLeftHandle = canMoveLeftHandle
        self.canMoveRightHandle = canMoveRightHandle
        self.isLeftHandleHidden = isLeftHandleHidden
        self.isRightHandleHidden = isRightHandleHidden
        self.onFineScrub = onFineScrub
        self.onFineScrubEnd = onFineScrubEnd
        self._currentStart = State(initialValue: start)
        self._currentEnd = State(initialValue: end)
        self.leftHandleMinPosition = leftHandleMinPosition
        self.leftHandleMaxPosition = leftHandleMaxPosition
        self.rightHandleMinPosition = rightHandleMinPosition
        self.rightHandleMaxPosition = rightHandleMaxPosition
        self.fineScrubbingDisabled = fineScrubbingDisabled
        self.onFineScrubAndDragStartLeft = onFineScrubAndDragStartLeft
        self.onFineScrubAndDragStartRight = onFineScrubAndDragStartRight
        self.onFineScrubAndDragEnd = onFineScrubAndDragEnd
        self.playbackState = playbackState
    }

    public var body: some View {
        ZStack(alignment: .leading) {
            waveformSelectorHandle(isLeft: true)
            // waveformSelectorHandle(isLeft: false) Keeping this until we need to support multi-handle selection
            waveformSelector
        }
        .opacity(playbackState != .playing ? 1.0 : 0.0)
        .frame(width: totalWidth, height: height)
        .onChange(of: start) { _, newStart in
            currentStart = newStart
        }
        .onChange(of: end) { _, newEnd in
            currentEnd = newEnd
        }
    }

    @ViewBuilder
    private func waveformSelectorHandle(isLeft: Bool) -> some View {
        WaveformSelectorHandle(
            position: isLeft ? start : end,
            otherPosition: isLeft ? end : start,
            isLeft: isLeft,
            totalWidth: totalWidth,
            height: height,
            duration: duration,
            minimumDuration: minimumDuration,
            maximumDuration: maximumDuration,
            onDrag: { position in
                if isLeft {
                    currentStart = position
                } else {
                    currentEnd = position
                }
                onLeftHandleDrag(position)
            },
            onDragEnd: onLeftHandleDragEnd,
            canMove: canMoveLeftHandle,
            isHidden: isLeftHandleHidden,
            onFineScrub: onFineScrub,
            onFineScrubEnd: onFineScrubEnd,
            minPosition: isLeft ? leftHandleMinPosition : rightHandleMinPosition,
            maxPosition: isLeft ? leftHandleMaxPosition : rightHandleMaxPosition,
            fineScrubbingDisabled: fineScrubbingDisabled,
            onFineScrubAndDragStartLeft: onFineScrubAndDragStartLeft,
            onFineScrubAndDragStartRight: onFineScrubAndDragStartRight,
            onFineScrubAndDragEnd: onFineScrubAndDragEnd
        )
    }

    @ViewBuilder
    private var waveformSelector: some View {
        RoundedRectangle(cornerRadius: 8)
            .strokeBorder(Color.SemanticV1.iconLink, lineWidth: 3)
            .background(
                RoundedRectangle(cornerRadius: 8)
                    .fill(Color.SemanticV1.iconLink.opacity(0.3))
            )
            .frame(
                width: max(0, (currentEnd - currentStart) * totalWidth),
                height: height
            )
            .offset(x: currentStart * totalWidth)
    }
}
