import SwiftUI

struct AudioTrimmer: View {
    @Binding var selectionStart: Double // 0.0 to 1.0
    @Binding var selectionEnd: Double   // 0.0 to 1.0
    @Binding var isPlaying: Bool // Whether audio is playing
    @State private var playheadPosition: Double = 0.0 // 0.0 to 1.0
    @State private var animationTimer: Timer?
    @State private var animationStartTime: Date?
    @State private var animationStartPosition: Double = 0.0
    @State private var isDraggingSelection = false
    @State private var isDraggingStartHandle = false
    @State private var isDraggingEndHandle = false
    @State private var dragStartPosition: CGFloat = 0
    @State private var originalSelectionStart: Double = 0
    @State private var originalSelectionEnd: Double = 0
    
    let onSelectionChanged: ((Double, Double) -> Void)?
    let totalDuration: TimeInterval // Total audio duration in seconds
    
    // Sample waveform data - heights normalized to 0.0-1.0
    private let waveformData: [Double] = [
        0.28, 0.47, 0.22, 0.19, 0.67, 0.87, 0.38, 0.76, 0.09, 0.49, 0.18, 0.66, 0.99, 0.38, 0.46, 0.24,
        0.96, 0.27, 0.37, 0.52, 0.73, 0.93, 0.94, 0.32, 0.68, 0.93, 0.24, 0.01, 0.58, 0.75, 0.29, 0.33,
        0.72, 0.57, 0.43, 0.79, 0.02, 0.42, 0.52, 0.55, 0.72, 0.88, 0.59, 0.14, 0.57, 0.92, 0.58, 0.52,
        0.88, 0.53, 0.67, 0.47, 0.59, 0.09, 0.94, 0.80, 0.01, 0.79, 0.31, 0.97, 0.91, 0.46, 0.87, 0.03,
        0.04, 0.98, 0.29, 0.03, 0.58, 0.37, 0.83, 0.46, 0.82, 0.80, 0.53, 0.82, 0.14, 0.55, 0.75, 0.35,
        0.62, 0.03, 0.91, 0.52, 0.04, 0.55, 0.99, 0.54, 0.17, 0.99, 0.35, 0.54, 0.91, 0.54, 0.06, 0.70,
        0.33, 0.57, 0.27, 0.40, 0.47, 0.29, 0.85, 0.44, 0.20, 0.97, 0.57, 0.68, 0.20, 0.47, 0.01, 0.48,
        0.43, 0.59, 0.24, 0.73, 0.72, 0.32, 0.85, 0.47, 0.69, 0.73, 0.42, 0.63, 0.33, 0.39, 0.24, 0.98
    ]
    
    init(
        selectionStart: Binding<Double>,
        selectionEnd: Binding<Double>,
        isPlaying: Binding<Bool> = .constant(false),
        totalDuration: TimeInterval = 180.0, // Default 3 minutes
        onSelectionChanged: ((Double, Double) -> Void)? = nil
    ) {
        self._selectionStart = selectionStart
        self._selectionEnd = selectionEnd
        self._isPlaying = isPlaying
        self.totalDuration = totalDuration
        self.onSelectionChanged = onSelectionChanged
    }
    
    // Helper function to format time duration
    private func formatTime(_ seconds: TimeInterval) -> String {
        let minutes = Int(seconds) / 60
        let remainingSeconds = Int(seconds) % 60
        return String(format: "%d:%02d", minutes, remainingSeconds)
    }
    
    var body: some View {
        GeometryReader { geometry in
            let cornerRadius = min(geometry.size.width * 0.03, 12) // Responsive corner radius
            let padding = max(geometry.size.width * 0.04, 12) // Responsive padding
            let maxWaveHeight: CGFloat = 48 // Fixed max height
            let minWaveHeight: CGFloat = 8 // Fixed min height  
            let barWidth: CGFloat = 3 // Fixed bar width
            let spacing: CGFloat = 3 // Fixed spacing
            
            // Calculate available width and how many bars we can show
            let availableWidth = geometry.size.width - (padding * 2)
            let totalBarAndSpacingWidth = barWidth + spacing
            let maxBars = max(0, Int(availableWidth / totalBarAndSpacingWidth))
            let visibleWaveformData = Array(waveformData.prefix(maxBars))
            
            ZStack {
                // Background with rounded corners
                RoundedRectangle(cornerRadius: cornerRadius)
                    .fill(Color.clear)
                    .overlay(
                        RoundedRectangle(cornerRadius: cornerRadius)
                            .stroke(Constants.Colors.Border.primary, lineWidth: 1)
                    )
                
                // Waveform visualization
                HStack(spacing: spacing) {
                    ForEach(Array(visibleWaveformData.enumerated()), id: \.offset) { index, amplitude in
                        // Calculate the position of this bar within the full container width
                        let barPositionInWaveform = Double(index) / Double(visibleWaveformData.count)
                        let waveformStart = Double(padding) / Double(geometry.size.width)
                        let waveformEnd = Double(geometry.size.width - padding) / Double(geometry.size.width)
                        let waveformWidth = waveformEnd - waveformStart
                        let barPositionInContainer = waveformStart + (barPositionInWaveform * waveformWidth)
                        
                        let isInSelection = barPositionInContainer >= selectionStart && barPositionInContainer <= selectionEnd
                        
                        RoundedRectangle(cornerRadius: 100)
                            .fill(isInSelection ? Constants.Colors.Foreground.primary : Constants.Colors.Foreground.primary.opacity(0.3))
                            .frame(width: barWidth, height: max(minWaveHeight, amplitude * maxWaveHeight))
                    }
                }
                .padding(padding)
                
                // Selection overlay
                selectionOverlay(geometry: geometry, padding: padding)
                
                // Playhead
                playheadOverlay(geometry: geometry)
                
                // Tooltips
                tooltipOverlay(geometry: geometry, padding: padding)
            }
        }
        .frame(height: 80)
        .onAppear {
            // Start playhead at playable start when component appears
            let handlePaddingRatio = 0.03 // 3% padding for handles
            playheadPosition = selectionStart + handlePaddingRatio
        }
        .onChange(of: isPlaying) { _, newValue in
            if newValue {
                startPlayheadAnimation()
            } else {
                stopPlayheadAnimation()
            }
        }
        .onChange(of: selectionStart) { _, newValue in
            // Reset playhead to start of playable area when selection changes and not playing
            if !isPlaying {
                let handlePaddingRatio = 0.03 // 3% padding for handles
                playheadPosition = newValue + handlePaddingRatio
            }
        }
    }
    
    @ViewBuilder
    private func playheadOverlay(geometry: GeometryProxy) -> some View {
        let totalWidth = geometry.size.width
        let handleWidth: CGFloat = 12
        
        // Calculate the playable area (selection minus handle widths)
        let handlePaddingRatio = handleWidth / totalWidth
        let playableStart = selectionStart + handlePaddingRatio
        let playableEnd = selectionEnd - handlePaddingRatio
        
        // Always show playhead when playing, constrain it to playable area
        if isPlaying || (playheadPosition >= selectionStart && playheadPosition <= selectionEnd) {
            let constrainedPlayhead = max(playableStart, min(playableEnd, playheadPosition))
            let playheadX = constrainedPlayhead * totalWidth
            
            RoundedRectangle(cornerRadius: 100)
                .fill(Constants.Colors.Foreground.primary)
                .frame(width: 2, height: geometry.size.height)
                .position(x: playheadX, y: geometry.size.height/2)
                .shadow(color: .black.opacity(0.3), radius: 2, x: 1, y: 4)
        }
    }
    
    private func startPlayheadAnimation() {
        guard selectionEnd > selectionStart else { return }
        
        // Calculate playable area (accounting for handle width)
        let handlePaddingRatio = 0.03 // 3% padding for handles
        let playableStart = selectionStart + handlePaddingRatio
        let playableEnd = selectionEnd - handlePaddingRatio
        
        guard playableEnd > playableStart else { return }
        
        // If playhead is outside playable area, reset to start
        if playheadPosition < playableStart || playheadPosition > playableEnd {
            playheadPosition = playableStart
        }
        
        // Store animation start values
        animationStartTime = Date()
        animationStartPosition = playheadPosition
        
        // Start timer-based animation
        animationTimer = Timer.scheduledTimer(withTimeInterval: 1.0/60.0, repeats: true) { _ in
            updatePlayheadPosition(playableStart: playableStart, playableEnd: playableEnd)
        }
    }
    
    private func updatePlayheadPosition(playableStart: Double, playableEnd: Double) {
        guard isPlaying,
              let startTime = animationStartTime else { return }
        
        let elapsed = Date().timeIntervalSince(startTime)
        let totalRange = playableEnd - playableStart
        let totalDuration = totalRange * self.totalDuration
        
        // Calculate how far we should be in the current loop
        let loopTime = elapsed.truncatingRemainder(dividingBy: totalDuration)
        let loopProgress = loopTime / totalDuration
        
        // Update position based on progress through current loop
        playheadPosition = playableStart + (loopProgress * totalRange)
    }
    
    private func stopPlayheadAnimation() {
        // Stop the timer immediately
        animationTimer?.invalidate()
        animationTimer = nil
        animationStartTime = nil
    }
    
    @ViewBuilder
    private func selectionOverlay(geometry: GeometryProxy, padding: CGFloat) -> some View {
        let totalWidth = geometry.size.width // Use full container width for handle movement
        let selectionWidth = (selectionEnd - selectionStart) * totalWidth
        let selectionX = selectionStart * totalWidth // Remove padding offset
        let handleWidth: CGFloat = 12 // Fixed handle width
        
        ZStack {
            // Selection background
            Rectangle()
                .fill(Constants.Colors.Accent.brand.opacity(0.1))
                .frame(width: selectionWidth, height: geometry.size.height)
                .position(x: selectionX + selectionWidth/2, y: geometry.size.height/2)
            
            // Left handle
            UnevenRoundedRectangle(
                topLeadingRadius: 4,
                bottomLeadingRadius: 4,
                bottomTrailingRadius: 0,
                topTrailingRadius: 0
            )
            .fill(Constants.Colors.Accent.brand)
            .frame(width: handleWidth, height: geometry.size.height + 1)
            .position(x: selectionX, y: geometry.size.height/2)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            if !isDraggingStartHandle {
                                isDraggingStartHandle = true
                                originalSelectionStart = selectionStart
                                originalSelectionEnd = selectionEnd
                            }
                            
                            let translation = value.translation.width / totalWidth
                            let newStart = max(0, min(originalSelectionStart + translation, selectionEnd - 0.05))
                            
                            selectionStart = newStart
                            onSelectionChanged?(selectionStart, selectionEnd)
                        }
                        .onEnded { _ in
                            isDraggingStartHandle = false
                        }
                )
            
            // Right handle
            UnevenRoundedRectangle(
                topLeadingRadius: 0,
                bottomLeadingRadius: 0,
                bottomTrailingRadius: 4,
                topTrailingRadius: 4
            )
            .fill(Constants.Colors.Accent.brand)
            .frame(width: handleWidth, height: geometry.size.height + 1)
            .position(x: selectionX + selectionWidth, y: geometry.size.height/2)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            if !isDraggingEndHandle {
                                isDraggingEndHandle = true
                                originalSelectionStart = selectionStart
                                originalSelectionEnd = selectionEnd
                            }
                            
                            let translation = value.translation.width / totalWidth
                            let newEnd = min(1.0, max(originalSelectionEnd + translation, selectionStart + 0.05))
                            
                            selectionEnd = newEnd
                            onSelectionChanged?(selectionStart, selectionEnd)
                        }
                        .onEnded { _ in
                            isDraggingEndHandle = false
                        }
                )
            
            // Selection area drag gesture (for moving the entire selection)
            Rectangle()
                .fill(Color.clear)
                .frame(width: max(selectionWidth - (handleWidth * 2), 0), height: geometry.size.height) // Exclude handle areas
                .position(x: selectionX + selectionWidth/2, y: geometry.size.height/2)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            if !isDraggingSelection && !isDraggingStartHandle && !isDraggingEndHandle {
                                isDraggingSelection = true
                                originalSelectionStart = selectionStart
                                originalSelectionEnd = selectionEnd
                            }
                            
                            if isDraggingSelection {
                                let selectionSize = originalSelectionEnd - originalSelectionStart
                                let translation = value.translation.width / totalWidth
                                let newStart = max(0, min(originalSelectionStart + translation, 1.0 - selectionSize))
                                let newEnd = newStart + selectionSize
                                
                                selectionStart = newStart
                                selectionEnd = newEnd
                                onSelectionChanged?(selectionStart, selectionEnd)
                            }
                        }
                        .onEnded { _ in
                            isDraggingSelection = false
                        }
                )
        }
        .overlay(
            // Selection border
            Rectangle()
                .stroke(Constants.Colors.Accent.brand, lineWidth: 1)
                .frame(width: selectionWidth, height: geometry.size.height)
                .position(x: selectionX + selectionWidth/2, y: geometry.size.height/2)
        )
    }
    
    @ViewBuilder
    private func tooltipOverlay(geometry: GeometryProxy, padding: CGFloat) -> some View {
        let totalWidth = geometry.size.width // Use full container width for tooltip positioning
        let selectionWidth = (selectionEnd - selectionStart) * totalWidth
        let selectionX = selectionStart * totalWidth
        
        // Left handle tooltip
        if isDraggingStartHandle {
            let startTime = selectionStart * totalDuration
            TooltipView(text: formatTime(startTime))
                .position(x: selectionX, y: -20) // 20pt above the handle
        }
        
        // Right handle tooltip  
        if isDraggingEndHandle {
            let endTime = selectionEnd * totalDuration
            TooltipView(text: formatTime(endTime))
                .position(x: selectionX + selectionWidth, y: -20) // 20pt above the handle
        }
    }
}

struct TooltipView: View {
    let text: String
    
    var body: some View {
        Text(text)
            .font(Constants.Typography.timecode) // 12pt medium font
            .foregroundColor(Constants.Colors.Foreground.primary)
            .tracking(0.24)
            .lineLimit(1)
            .padding(.horizontal, 12)
            .padding(.vertical, 8)
            .background(
                RoundedRectangle(cornerRadius: 8)
                    .fill(Constants.Colors.Background.Fog.thick) // #ffffff1a
                    .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 8))
            )
    }
}

// MARK: - Preview
#Preview {
    @Previewable @State var start: Double = 0.0
    @Previewable @State var end: Double = 0.4
    @Previewable @State var playing: Bool = false
    
    VStack(spacing: 20) {
        AudioTrimmer(
            selectionStart: $start,
            selectionEnd: $end,
            isPlaying: $playing,
            totalDuration: 240.0, // 4 minute sample audio
            onSelectionChanged: { newStart, newEnd in
                print("Selection changed: \(newStart) - \(newEnd)")
            }
        )
        
        VStack(alignment: .leading, spacing: 8) {
            Text("Selection: \(String(format: "%.2f", start)) - \(String(format: "%.2f", end))")
                .font(Constants.Typography.small)
                .foregroundColor(Constants.Colors.Foreground.primary)
            
            Text("Duration: \(String(format: "%.2f", end - start)) (\(String(format: "%.1f", (end - start) * 100))%)")
                .font(Constants.Typography.xSmallRegular)
                .foregroundColor(Constants.Colors.Foreground.tertiary)
        }
    }
    .padding()
    .background(Constants.Colors.Background.primary)
}
