import SwiftUI

/// A view that drives a recording session.
///
/// The view shows a main button that starts, pauses, and resumes a recording, with a label above it displaying the elapsed recording time.
/// While paused, a send button lets the user submit the recording for processing, showing a progress indicator until the processing finishes.
///
/// All state and control behavior lives in the view's ``Model``; the view itself only renders it and forwards button presses and state changes.
public struct RecordingView: View {
    
    // MARK: Properties
    
    /// The model that owns the recording state and drives the view's controls.
    @State private var model: Model

    /// The closure invoked with the transcription of every processed recording.
    private let onTranscription: (Transcription) -> Void

    // MARK: Initializers

    /// Creates a recording view in the not-recording state, attached to the given recording and transcribing services.
    ///
    /// - Parameters:
    ///   - capturer: The service that captures the audio from a microphone.
    ///   - transcriber: The service that transcribes the recorded audio into text.
    ///   - locale: The binding to the locale of the spoken language to transcribe.
    ///   - onTranscription: The closure invoked with the transcription of every processed recording. Defaults to a closure that does nothing.
    public init(
        capturer: any Capturing,
        transcriber: any Transcribing,
        locale: Binding<Locale>,
        onTranscription: @escaping (Transcription) -> Void
    ) {
        self.model = .init(
            capturer: capturer,
            transcribe: transcriber,
            locale: locale
        )
        self.onTranscription = onTranscription
    }

    // MARK: Body

    /// The content of the view: the timer label above the main and send buttons, with every change of the model's state forwarded back
    /// to ``Model/updatedState(shouldRestartTimer:)``.
    public var body: some View {
        VStack(
            spacing: Constant.Spacing.stack
        ) {
            if model.shouldShowTimer {
                Text(model.textTimer)
                    .font(.largeTitle)
                    .fontWeight(.bold)
                    .foregroundStyle(.primary)
                    .monospacedDigit()
                    .contentTransition(.numericText())
                    .animation(
                        .easeInOut,
                        value: model.textTimer
                    )
            }
            
            GlassEffectContainer {
                HStack(
                    spacing: Constant.Spacing.stack
                ) {
                    Button {
                        model.pressedMain()
                    } label: {
                        Image(model.iconMain)
                            .resizable()
                            .scaledToFit()
                    }
                    .buttonStyle(.recording(
                        invertStyle: true
                    ))
                    .disabled(model.shouldDisableMain)

                    if model.shouldShowSend {
                        Button {
                            model.pressedSend()
                        } label: {
                            if let icon = model.iconSend {
                                Image(icon)
                                    .resizable()
                            } else {
                                ProgressView()
                            }
                        }
                        .buttonStyle(.recording(
                            invertStyle: !model.isProcessing
                        ))
                        .disabled(model.isProcessing)
                    }
                }
            }
        }
        .onChange(
            of: model.state,
            initial: false
        ) { oldValue, _ in
            model.updatedState(
                shouldRestartTimer: oldValue == .notRecording
            )
        }
        .onChange(
            of: model.transcription,
            initial: false
        ) { _, newValue in
            if let newValue {
                onTranscription(newValue)
            }
        }
    }

}

// MARK: - Constants

/// The constant values used across the view.
private enum Constant {
    /// The spacing constants.
    enum Spacing {
        /// The spacing between the elements of a stack.
        static let stack: CGFloat = 8
    }
}

// MARK: - Previews

#Preview(
    "Recording view"
) {
    RecordingView(
        capturer: DummyCapturing(),
        transcriber: DummyTranscribing(),
        locale: .constant(.current)
    ) { _ in
        // On transcription closure.
    }
}
