import SwiftUI

/// The record surface in the composer: a mic button that, once tapped (or
/// auto-started), shows the elapsed time and a live level meter with Stop /
/// Discard. When recording ends it hands the finished `(url, duration)` up via
/// `onFinish`; the composer owns everything after that.
struct AudioRecordingControl: View {
    @Environment(AudioRecorderService.self) private var recorder

    /// Begin recording as soon as the view appears (the toolbar "record a note"
    /// entry point), after the permission prompt resolves.
    var autostart = false
    let onFinish: (URL, TimeInterval) -> Void

    @State private var permissionDenied = false
    @State private var startError: String?
    @State private var didAutostart = false

    var body: some View {
        VStack(spacing: 12) {
            if permissionDenied {
                deniedState
            } else if recorder.isRecording {
                recordingState
            } else {
                idleState
            }

            if let startError {
                Text(startError)
                    .font(.footnote)
                    .foregroundStyle(.red)
            }
        }
        .frame(maxWidth: .infinity)
        .task {
            recorder.onInterrupted = { recording in onFinish(recording.url, recording.duration) }
            if autostart, !didAutostart {
                didAutostart = true
                await beginRecording()
            }
        }
        .onDisappear {
            recorder.onInterrupted = nil
            if recorder.isRecording { recorder.discard() }
        }
    }

    private var idleState: some View {
        Button {
            Task { await beginRecording() }
        } label: {
            VStack(spacing: 6) {
                Image(systemName: "mic.circle.fill")
                    .font(.system(size: 52))
                    .foregroundStyle(.tint)
                Text("Record")
                    .font(.callout)
            }
        }
        .buttonStyle(.plain)
    }

    private var recordingState: some View {
        VStack(spacing: 14) {
            LevelMeter(level: recorder.level)

            Text(AudioPlayerView.timeString(recorder.elapsed))
                .font(.title2.monospacedDigit())
                .foregroundStyle(.primary)

            HStack(spacing: 24) {
                Button(role: .destructive) {
                    recorder.discard()
                } label: {
                    Label("Discard", systemImage: "trash")
                }
                .buttonStyle(.bordered)

                Button {
                    if let finished = recorder.stopRecording() {
                        onFinish(finished.url, finished.duration)
                    }
                } label: {
                    Label("Stop", systemImage: "stop.circle.fill")
                }
                .buttonStyle(.borderedProminent)
            }
        }
    }

    private var deniedState: some View {
        VStack(spacing: 8) {
            Image(systemName: "mic.slash.circle.fill")
                .font(.system(size: 44))
                .foregroundStyle(.secondary)
            Text("Microphone access is off. Enable it for Contextful in Settings to record voice notes.")
                .font(.footnote)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
        }
    }

    private func beginRecording() async {
        startError = nil
        guard await recorder.requestPermission() else {
            permissionDenied = true
            return
        }
        permissionDenied = false
        do {
            try recorder.startRecording()
        } catch {
            startError = "Couldn't start recording: \(error.localizedDescription)"
        }
    }
}

/// A small row of bars whose height rides the current input level — enough to
/// show the mic is live without pretending to be a real waveform.
private struct LevelMeter: View {
    let level: Float

    private let barCount = 9
    /// Fixed per-bar weights so the meter has a stable, mic-like shape.
    private let weights: [CGFloat] = [0.35, 0.55, 0.75, 0.9, 1.0, 0.9, 0.75, 0.55, 0.35]

    var body: some View {
        HStack(alignment: .center, spacing: 4) {
            ForEach(0..<barCount, id: \.self) { index in
                Capsule()
                    .fill(.tint)
                    .frame(width: 4, height: height(index))
            }
        }
        .frame(height: 40)
        .animation(.easeOut(duration: 0.08), value: level)
    }

    private func height(_ index: Int) -> CGFloat {
        let base: CGFloat = 4
        let peak: CGFloat = 36
        return base + peak * CGFloat(level) * weights[index]
    }
}
