use crate::audio::recorder::AudioRecorder;
use crate::engine::ParakeetEngine;
use cpal::Device;
use parking_lot::Mutex;
use serde::Serialize;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};

#[derive(Debug, Clone, Serialize)]
pub struct MicInfo {
    pub id: String,
    pub label: String,
}

pub struct AudioState {
    pub recorder: Mutex<Option<AudioRecorder>>,
    pub engine: Mutex<Option<ParakeetEngine>>,
    pub current_file_name: Mutex<Option<String>>,
    recording_mode: AtomicU8,
    recording_trigger: AtomicU8,
    /// Flag indicating recording duration limit has been reached
    pub limit_reached: std::sync::Arc<AtomicBool>,
    /// Cached audio input device to avoid re-enumerating devices on each recording
    pub cached_device: Mutex<Option<Device>>,
    /// Wake word to strip from the end of the transcription (set by validate trigger)
    pub strip_word: Mutex<Option<String>>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum RecordingMode {
    Standard = 0,
    Llm = 1,
    Command = 2,
}

impl From<u8> for RecordingMode {
    fn from(val: u8) -> Self {
        match val {
            0 => RecordingMode::Standard,
            1 => RecordingMode::Llm,
            2 => RecordingMode::Command,
            _ => RecordingMode::Standard,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum RecordingTrigger {
    Keyboard = 0,
    WakeWord = 1,
}

impl From<u8> for RecordingTrigger {
    fn from(val: u8) -> Self {
        match val {
            1 => RecordingTrigger::WakeWord,
            _ => RecordingTrigger::Keyboard,
        }
    }
}

impl AudioState {
    pub fn new() -> Self {
        Self {
            recorder: Mutex::new(None),
            engine: Mutex::new(None),
            current_file_name: Mutex::new(None),
            recording_mode: AtomicU8::new(RecordingMode::Standard as u8),
            recording_trigger: AtomicU8::new(RecordingTrigger::Keyboard as u8),
            limit_reached: std::sync::Arc::new(AtomicBool::new(false)),
            cached_device: Mutex::new(None),
            strip_word: Mutex::new(None),
        }
    }

    pub fn set_recording_mode(&self, mode: RecordingMode) {
        self.recording_mode.store(mode as u8, Ordering::SeqCst);
    }

    pub fn get_recording_mode(&self) -> RecordingMode {
        self.recording_mode.load(Ordering::SeqCst).into()
    }

    pub fn set_recording_trigger(&self, trigger: RecordingTrigger) {
        self.recording_trigger
            .store(trigger as u8, Ordering::SeqCst);
    }

    pub fn get_recording_trigger(&self) -> RecordingTrigger {
        self.recording_trigger.load(Ordering::SeqCst).into()
    }

    pub fn is_limit_reached(&self) -> bool {
        self.limit_reached.load(Ordering::SeqCst)
    }

    pub fn get_limit_reached_arc(&self) -> std::sync::Arc<AtomicBool> {
        self.limit_reached.clone()
    }

    /// Sets the cached audio device
    pub fn set_cached_device(&self, device: Option<Device>) {
        *self.cached_device.lock() = device;
    }

    /// Gets a clone of the cached audio device
    pub fn get_cached_device(&self) -> Option<Device> {
        self.cached_device.lock().clone()
    }
}
