import AVFoundation
import ComponentLibrary
import ComposableArchitecture
import SwiftUI
import Localization
import APIClient
import SunoModelClient

public struct ChatAudioTrimmerView: View {
    @Bindable var store: StoreOf<ChatAudioRecorder>
    @State private var isEditingTitle: Bool = false
    @FocusState private var isTitleFieldFocused: Bool

    private static let dateComponentsFormatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.minute, .second]
        formatter.zeroFormattingBehavior = .pad
        formatter.unitsStyle = .positional
        return formatter
    }()

    public init(store: StoreOf<ChatAudioRecorder>) {
        self.store = store
    }

    public var body: some View {
        VStack(spacing: 0) {
            // Editable title
            HStack(spacing: 4) {
                Spacer()
                if isEditingTitle {
                    CharacterLimitedTextField(
                        placeholder: "Untitled",
                        text: $store.title,
                        characterLimit: store.titleCharCountLimit
                    )
                    .typographyV1(
                        TypographyV1.bodyMedium
                            .lineHeight(24)
                            .kerning(0.32)
                    )
                    .foregroundColor(ChatConstants.Colors.Foreground.primary)
                    .multilineTextAlignment(.center)
                    .textFieldStyle(.plain)
                    .focused($isTitleFieldFocused)
                    .onSubmit {
                        isEditingTitle = false
                        isTitleFieldFocused = false
                    }
                    .onAppear {
                        isTitleFieldFocused = true
                        store.send(.clearUntitledTitle)
                    }
                } else {
                    HStack(spacing: 4) {
                        Text(store.title)
                            .typographyV1(
                                TypographyV1.bodyMedium
                                    .lineHeight(24)
                                    .kerning(0.32)
                            )
                            .foregroundColor(ChatConstants.Colors.Foreground.primary)
                        Image.FigmaMCP.edit
                            .resizable()
                            .renderingMode(.template)
                            .frame(width: 16, height: 16)
                            .foregroundColor(ChatConstants.Colors.Foreground.primary)
                    }
                    .onTapGesture {
                        store.send(.clearUntitledTitle)
                        isEditingTitle = true
                        isTitleFieldFocused = true
                    }
                }
                Spacer()
            }
            .padding(.horizontal, 24)
            .padding(.top, 56)
            .padding(.bottom, 24)

            Spacer()

            // Trimmer component
            VStack(spacing: 16) {
                HStack(spacing: 16) {
                    // Play button
                    Button {
                        if store.isPlaying {
                            store.send(.pausePreview)
                        } else {
                            store.send(.playPreview)
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 12)
                                .fill(ChatConstants.Colors.Background.Fog.thin)
                                .frame(width: 80, height: 80)

                            if store.isPlaying {
                                Image(systemName: "pause.fill")
                                    .font(.system(size: 24))
                                    .foregroundColor(ChatConstants.Colors.Foreground.primary)
                            } else {
                                Image(systemName: "play.fill")
                                    .font(.system(size: 24))
                                    .foregroundColor(ChatConstants.Colors.Foreground.primary)
                            }
                        }
                    }
                    .buttonStyle(PlainButtonStyle())
                    .disabled(store.showProgressView)

                    // Waveform trimmer
                    if store.duration > 0 {
                        ChatAudioWaveformTrimmer(
                            store: store,
                            samples: convertSamplesToArray(store.samples, duration: store.duration)
                        )
                        .frame(height: 80)
                    } else {
                        // Placeholder while loading
                        RoundedRectangle(cornerRadius: 12)
                            .fill(ChatConstants.Colors.Background.Fog.thin)
                            .frame(height: 80)
                    }
                }
                .padding(.horizontal, 24)
            }

            Spacer()

            VStack(spacing: 0) {
                HStack(spacing: 9) {
                    // Cancel button
                    Button {
                        store.send(.cancelTrim)
                    } label: {
                        Text("Cancel")
                            .typographyV1(
                                TypographyV1.bodyLarge
                                    .lineHeight(24)
                                    .kerning(0.36)
                            )
                            .foregroundColor(ChatConstants.Colors.Foreground.primary)
                            .frame(maxWidth: .infinity)
                            .frame(height: 56)
                            .background(ChatConstants.Colors.Background.tertiary)
                            .cornerRadius(100)
                    }
                    .buttonStyle(PlainButtonStyle())

                    // Continue button
                    Button {
                        store.send(.confirmTrim)
                    } label: {
                        Text("Continue")
                            .typographyV1(
                                TypographyV1.bodyLarge
                                    .lineHeight(24)
                                    .kerning(0.36)
                            )
                            .foregroundColor(ChatConstants.Colors.Background.primary)
                            .frame(maxWidth: .infinity)
                            .frame(height: 56)
                            .background(ChatConstants.Colors.Foreground.primary)
                            .cornerRadius(100)
                    }
                    .buttonStyle(PlainButtonStyle())
                    .disabled(store.showProgressView)
                }
                .padding(.horizontal, 24)
                .padding(.top, 24)

                // Footer text
                AudioLengthCaptionView()
                    .padding(.horizontal, 24)
                    .padding(.top, 16)
                    .padding(.bottom, 24)
            }
        }
        .task {
            store.send(.setupAudioPlayer)
        }
        .onDisappear {
            store.send(.teardownAudioPlayer)
        }
    }

    private func convertSamplesToArray(_ samples: [TimeInterval: CGFloat], duration: TimeInterval) -> [Float] {
        // Convert time-based samples to position-based array for trimmer
        // Create array with 100 points (adjust based on trimmer needs)
        let pointCount = 100

        // Pre-process samples
        let bucketSize = duration / Double(pointCount)
        var preprocessedSamples: [Int: CGFloat] = [:]

        for (sampleTime, value) in samples {
            let bucketIndex = Int(sampleTime / bucketSize)
            let clampedIndex = min(max(bucketIndex, 0), pointCount - 1)
            // Keep the maximum value in each bucket for better visualization
            if let existing = preprocessedSamples[clampedIndex] {
                preprocessedSamples[clampedIndex] = max(existing, value)
            } else {
                preprocessedSamples[clampedIndex] = value
            }
        }

        // Build waveform array using preprocessed samples
        var waveformArray: [Float] = []
        for i in 0..<pointCount {
            if let value = preprocessedSamples[i] {
                waveformArray.append(Float(value))
            } else {
                // Check adjacent buckets if current bucket is empty
                var foundValue: CGFloat?
                for offset in -1...1 {
                    let checkIndex = i + offset
                    if checkIndex >= 0 && checkIndex < pointCount, let value = preprocessedSamples[checkIndex] {
                        foundValue = value
                        break
                    }
                }
                waveformArray.append(Float(foundValue ?? 0.3)) // Default fallback
            }
        }

        return waveformArray
    }
}

// Waveform trimmer component
struct ChatAudioWaveformTrimmer: View {
    @Bindable var store: StoreOf<ChatAudioRecorder>
    let samples: [Float]

    private var selectionStart: Double {
        store.duration > 0 ? store.trimStartTime / store.duration : 0
    }

    private var selectionEnd: Double {
        store.duration > 0 ? store.trimEndTime / store.duration : 0
    }

    private let placeholderWaveformData: [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
    ]

    var body: some View {
        GeometryReader { geometry in
            let cornerRadius: CGFloat = 12
            let padding: CGFloat = 12
            let maxWaveHeight: CGFloat = 48
            let minWaveHeight: CGFloat = 8
            let barWidth: CGFloat = 3
            let spacing: CGFloat = 3

            let availableWidth = geometry.size.width - (padding * 2)
            let totalBarAndSpacingWidth = barWidth + spacing
            let maxBars = max(0, Int(availableWidth / totalBarAndSpacingWidth))

            ZStack {
                // Background with border
                RoundedRectangle(cornerRadius: cornerRadius)
                    .fill(Color.clear)
                    .overlay(
                        RoundedRectangle(cornerRadius: cornerRadius)
                            .stroke(ChatConstants.Colors.Border.primary, lineWidth: 1)
                    )

                // Waveform visualization
                HStack(spacing: spacing) {
                    let waveformData = samples.isEmpty ? placeholderWaveformData.map { Float($0) } : samples
                    let visibleData = Array(waveformData.prefix(maxBars))

                    ForEach(Array(visibleData.enumerated()), id: \.offset) { index, amplitude in
                        let barPositionInWaveform = Double(index) / Double(visibleData.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 ? ChatConstants.Colors.Foreground.primary : ChatConstants.Colors.Foreground.primary.opacity(0.3))
                            .frame(width: barWidth, height: max(minWaveHeight, CGFloat(amplitude) * maxWaveHeight))
                    }
                }
                .padding(padding)

                // Selection overlay with handles
                selectionOverlay(geometry: geometry)

                // Playhead
                playheadOverlay(geometry: geometry, totalDuration: store.duration)
            }
        }
    }

    @ViewBuilder
    private func selectionOverlay(geometry: GeometryProxy) -> some View {
        let totalWidth = geometry.size.width
        let selectionWidth = (selectionEnd - selectionStart) * totalWidth
        let selectionX = selectionStart * totalWidth
        let handleWidth: CGFloat = 12

        ZStack {
            // Selection background with drag gesture
            Rectangle()
                .fill(ChatConstants.Colors.Accent.brand.opacity(0.1))
                .frame(width: selectionWidth, height: geometry.size.height)
                .position(x: selectionX + selectionWidth/2, y: geometry.size.height/2)
                .gesture(
                    DragGesture(minimumDistance: 10)
                        .onChanged { value in
                            guard !store.isDraggingStartHandle && !store.isDraggingEndHandle else { return }
                            if !store.isDraggingSelection {
                                store.send(.dragSelectionStarted)
                            }
                            store.send(.dragSelectionChanged(translation: value.translation.width, totalWidth: totalWidth))
                        }
                        .onEnded { _ in
                            store.send(.dragSelectionEnded)
                        }
                )

            // Left handle
            UnevenRoundedRectangle(
                topLeadingRadius: 4,
                bottomLeadingRadius: 4,
                bottomTrailingRadius: 0,
                topTrailingRadius: 0
            )
            .fill(ChatConstants.Colors.Accent.brand)
            .frame(width: handleWidth, height: geometry.size.height + 1)
            .position(x: selectionX, y: geometry.size.height/2)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { value in
                        guard !store.isDraggingEndHandle && !store.isDraggingSelection else { return }
                        if !store.isDraggingStartHandle {
                            store.send(.dragStartHandleStarted)
                        }
                        store.send(.dragStartHandleChanged(translation: value.translation.width, totalWidth: totalWidth))
                    }
                    .onEnded { _ in
                        store.send(.dragStartHandleEnded)
                    }
            )

            // Right handle
            UnevenRoundedRectangle(
                topLeadingRadius: 0,
                bottomLeadingRadius: 0,
                bottomTrailingRadius: 4,
                topTrailingRadius: 4
            )
            .fill(ChatConstants.Colors.Accent.brand)
            .frame(width: handleWidth, height: geometry.size.height + 1)
            .position(x: selectionX + selectionWidth, y: geometry.size.height/2)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { value in
                        guard !store.isDraggingStartHandle && !store.isDraggingSelection else { return }
                        if !store.isDraggingEndHandle {
                            store.send(.dragEndHandleStarted)
                        }
                        store.send(.dragEndHandleChanged(translation: value.translation.width, totalWidth: totalWidth))
                    }
                    .onEnded { _ in
                        store.send(.dragEndHandleEnded)
                    }
            )
        }
        .overlay(
            // Selection border
            Rectangle()
                .stroke(ChatConstants.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 playheadOverlay(geometry: GeometryProxy, totalDuration: TimeInterval) -> some View {
        let totalWidth = geometry.size.width
        let handleWidth: CGFloat = 12
        let handlePaddingRatio = handleWidth / totalWidth
        let playableStart = selectionStart + handlePaddingRatio
        let playableEnd = selectionEnd - handlePaddingRatio

        if store.isPlaying || (store.playbackTime >= selectionStart * totalDuration && store.playbackTime <= selectionEnd * totalDuration) {
            let playbackProgress = store.playbackTime / totalDuration
            let constrainedPlayhead = max(playableStart, min(playableEnd, playbackProgress))
            let playheadX = constrainedPlayhead * totalWidth

            RoundedRectangle(cornerRadius: 100)
                .fill(ChatConstants.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)
        }
    }
}
