import ComponentLibrary
import ComposableArchitecture
import SwiftUI

public struct WaveformEditorView: View {
    let store: StoreOf<WaveformEditor>
    @State private var isDragging: Bool = false
    @State private var lastDragLocation: CGPoint?
    public init(store: StoreOf<WaveformEditor>) {
        self.store = store
    }

    public var body: some View {
        VStack(spacing: 0) {
            ZStack(alignment: .top) {
                waveformEditorBackground
                waveformStrip
                waveformStripTimeControls
                playbackCenterMarker
                waveformSelectorAndControls
                resetPlaybackStateButtonOverlay
            }
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { value in
                        guard store.playbackState.isActive,
                              !store.userIsInteractingWithLeftHandle,
                              !store.userIsInteractingWithRightHandle
                        else { return }

                        if !isDragging {
                            isDragging = true
                            store.send(.didStartDragWaveformStrip(location: value.location.x))
                            store.send(.didDragWaveformStripTo(translation: value.translation.width))
                        } else {
                            store.send(.didDragWaveformStripTo(translation: value.translation.width))
                        }
                    }
                    .onEnded { _ in
                        isDragging = false
                        store.send(.didEndDragWaveformStrip)
                    }
            )
            waveformEditorControls
        }
        .background(linearGradientBackground)
        .frame(width: store.waveformEditorWidth)
        .task {
            store.send(.task)
        }
    }

    @ViewBuilder
    var linearGradientBackground: some View {
        LinearGradient(
            colors: [
                .SemanticV1.backgroundSecondary.opacity(0.2),
                .SemanticV1.backgroundSecondary.opacity(1),
            ],
            startPoint: .top,
            endPoint: .bottom
        )
        .cornerRadius(8, corners: [UIRectCorner.bottomLeft, UIRectCorner.bottomRight])
    }

    @ViewBuilder
    var playbackCenterMarker: some View {
        Rectangle().frame(width: 1, height: store.waveformStripHeight)
            .foregroundColor(.SemanticV1.backgroundInvert)
            .opacity(store.shouldShowCenterMarker ? 1.0 : 0.0)
    }

    @ViewBuilder
    var waveformStrip: some View {
        WaveformStrip(store: store)
            .offset(x: store.waveformStripOffset, y: 0)
            .animation(.spring(response: 0.2, dampingFraction: 0.8, blendDuration: 0.1), value: store.waveformStripWidth)
            .frame(width: store.waveformEditorWidth, height: store.waveformStripHeight)
    }

    @ViewBuilder
    var waveformStripTimeControls: some View {
        WaveformStripTimeControls(
            width: store.waveformEditorWidth,
            height: store.waveformStripHeight,
            markerTime: store.markerTime,
            leftEdgeTime: store.fineScrubbingWaveformStripStartTimeFormatted,
            rightEdgeTime: store.fineScrubbingWaveformStripEndTimeFormatted,
            isFineScrubbing: store.isFineScrubbing,
            showLeftEdgeArrow: store.showWaveformStripControlsLeftSeekButton,
            showRightEdgeArrow: store.showWaveformStripControlsRightSeekButton,
            onTapMarkerTime: {
                store.send(.didTapWaveformStripControlsMarkerTime)
            },
            onTapLeftEdgeArrow: {
                store.send(.didTapWaveformStripControlsLeftSeekButton)
            },
            onTapRightEdgeArrow: {
                store.send(.didTapWaveformStripControlsRightSeekButton)
            },
            onHoldLeftEdgeArrow: {
                store.send(.didHoldWaveformStripControlsLeftSeekButton)
            },
            onHoldRightEdgeArrow: {
                store.send(.didHoldWaveformStripControlsRightSeekButton)
            },
            onHoldEnd: {
                store.send(.didEndScrolling)
            },
            isHighlightedPortionToTheRightOfVisibleWindow: store.isHighlightedPortionToTheRightOfVisibleWindow,
            isHighlightedPortionToTheLeftOfVisibleWindow: store.isHighlightedPortionToTheLeftOfVisibleWindow,
            onTapRecenterToHighlightedPortion: {
                store.send(.didTapRecenterToHighlightedPortion)
            }
        )
        .frame(width: store.waveformEditorWidth)
    }

    @ViewBuilder
    var waveformSelectorAndControls: some View {
        WaveformSelector(
            start: store.leftHandlePosition.positionValue(store.waveformEditorWidth, store.bufferWidth),
            end: store.rightHandlePosition.positionValue(store.waveformEditorWidth, store.bufferWidth),
            totalWidth: store.waveformEditorWidth,
            height: store.waveformStripHeight,
            duration: store.clipDuration,
            onLeftHandleDrag: { position in
                store.send(.didDragLeftHandleTo(position))
                store.send(.delegate(.isDraggingLeftHandle(store.leftHandleTime)))
            },
            onRightHandleDrag: { position in
                store.send(.didDragRightHandleTo(position))
            },
            onLeftHandleDragEnd: { position in
                store.send(.didEndDraggingLeftHandleTo(position))
            },
            onRightHandleDragEnd: { position in
                store.send(.didEndDraggingRightHandleTo(position))
            },
            canMoveLeftHandle: store.canMoveLeftHandle,
            canMoveRightHandle: store.canMoveRightHandle,
            isLeftHandleHidden: store.isLeftHandleHidden,
            isRightHandleHidden: store.isRightHandleHidden,
            onFineScrub: {
                store.send(.didFineScrub)
            },
            onFineScrubEnd: {
                store.send(.didEndFineScrubbing)
            },
            leftHandleMinPosition: store.leftHandleMinPosition,
            leftHandleMaxPosition: store.leftHandleMaxPosition,
            rightHandleMinPosition: store.rightHandleMinPosition,
            rightHandleMaxPosition: store.rightHandleMaxPosition,
            fineScrubbingDisabled: store.fineScrubbingDisabled,
            onFineScrubAndDragStartLeft: {
                store.send(.didStartScrollingLeft)
            },
            onFineScrubAndDragStartRight: {
                store.send(.didStartScrollingRight)
            },
            onFineScrubAndDragEnd: {
                store.send(.didEndScrolling)
            },
            playbackState: store.playbackState
        )
        .frame(width: store.waveformEditorWidth, height: store.waveformStripHeight)
        .opacity(store.isWaveformSelectorVisible ? 1.0 : 0.0)
        .clipShape(.rect(cornerRadius: 8))
        WaveformSelectorControls(
            showLeftHandleResetControl: store.showLeftHandleResetPositionControl,
            showRightHandleResetControl: store.showRightHandleResetPositionControl,
            onLeftHandleReset: {
                store.send(.didResetLeftHandle)
            },
            onRightHandleReset: {
                store.send(.didResetRightHandle)
            },
            bufferWidth: store.bufferWidth,
            totalWidth: store.waveformEditorWidth,
            height: store.waveformStripHeight
        )
        .frame(width: store.waveformEditorWidth, height: store.waveformStripHeight)
    }

    @ViewBuilder
    var waveformEditorBackground: some View {
        RoundedRectangle(cornerRadius: 8)
            .fill(Color.SemanticV1.backgroundTertiary)
            .frame(width: store.waveformEditorWidth, height: store.waveformStripHeight)
    }

    @ViewBuilder
    var waveformEditorControls: some View {
        WaveformEditorControls(
            isPlaying: Binding(
                get: { store.isPlaying },
                set: { _ in store.send(.togglePlayPause) }
            ),
            leftHandleTimeMarkerCaption: store.leftHandleTimeMarkerCaption,
            rightHandleTimeMarkerCaption: store.rightHandleTimeMarkerCaption,
            leftHandleTime: store.leftHandleTimeFormatted,
            rightHandleTime: store.rightHandleTimeFormatted,
            didManuallyEditLeftHandleTime: { time in
                store.send(.didManuallyEditLeftHandleTime(time))
            },
            didManuallyEditRightHandleTime: { time in
                store.send(.didManuallyEditRightHandleTime(time))
            },
            resetEditableTimestampFields: {
                store.send(.resetEditableTimestampFields)
            },
            isWaitingToPlay: store.isWaitingToPlay,
            shouldDismissKeyboard: store.shouldDismissKeyboard,
            shouldSaveTimestampsAndDismissKeyboard: store.shouldSaveTimestampsAndDismissKeyboard
        )
        .frame(width: store.waveformEditorWidth)
    }

    @ViewBuilder
    var resetPlaybackStateButtonOverlay: some View {
        Button {
            store.send(.didTapResetPlaybackStateButton)
        } label: {
            Circle()
                .fill(Color.SemanticV1.backgroundPrimary)
                .frame(width: 16, height: 16)
                .overlay(
                    Image(systemName: "arrow.counterclockwise")
                        .font(.system(size: 8, weight: .bold))
                        .foregroundColor(Color.SemanticV1.iconPrimary)
                )
                .frame(width: 32, height: 32)
                .contentShape(Circle())
        }
        .zIndex(store.showResetPlaybackStateButton ? .infinity : -1) // Shows this over other controls
        .opacity(store.showResetPlaybackStateButton ? 1 : 0)
        .frame(width: store.waveformEditorWidth, height: store.waveformStripHeight, alignment: .topTrailing)
    }
}
