//! Audio recorder — receives RTP packets and writes a WAV file.

use codec_lib::TranscodeState;
use std::path::Path;

/// Active recording session.
pub struct Recorder {
    writer: hound::WavWriter<std::io::BufWriter<std::fs::File>>,
    transcoder: TranscodeState,
    source_pt: u8,
    total_samples: u64,
    sample_rate: u32,
    max_samples: Option<u64>,
    file_path: String,
}

impl Recorder {
    /// Create a new recorder that writes to a WAV file.
    /// `source_pt` is the RTP payload type of the incoming audio.
    /// `max_duration_ms` optionally limits the recording length.
    pub fn new(
        file_path: &str,
        source_pt: u8,
        max_duration_ms: Option<u64>,
    ) -> Result<Self, String> {
        // Ensure parent directory exists.
        if let Some(parent) = Path::new(file_path).parent() {
            std::fs::create_dir_all(parent).map_err(|e| format!("create dir: {e}"))?;
        }

        let sample_rate = 8000u32; // Record at 8kHz (standard telephony)
        let spec = hound::WavSpec {
            channels: 1,
            sample_rate,
            bits_per_sample: 16,
            sample_format: hound::SampleFormat::Int,
        };

        let writer = hound::WavWriter::create(file_path, spec)
            .map_err(|e| format!("create WAV {file_path}: {e}"))?;

        let transcoder = TranscodeState::new().map_err(|e| format!("codec init: {e}"))?;

        let max_samples = max_duration_ms.map(|ms| (sample_rate as u64 * ms) / 1000);

        Ok(Self {
            writer,
            transcoder,
            source_pt,
            total_samples: 0,
            sample_rate,
            max_samples,
            file_path: file_path.to_string(),
        })
    }

    /// Create a recorder that writes raw PCM at a given sample rate.
    /// Used by tool legs that already have decoded PCM (no RTP processing needed).
    pub fn new_pcm(
        file_path: &str,
        sample_rate: u32,
        max_duration_ms: Option<u64>,
    ) -> Result<Self, String> {
        if let Some(parent) = Path::new(file_path).parent() {
            std::fs::create_dir_all(parent).map_err(|e| format!("create dir: {e}"))?;
        }

        let spec = hound::WavSpec {
            channels: 1,
            sample_rate,
            bits_per_sample: 16,
            sample_format: hound::SampleFormat::Int,
        };

        let writer = hound::WavWriter::create(file_path, spec)
            .map_err(|e| format!("create WAV {file_path}: {e}"))?;

        // source_pt is unused for PCM recording; set to 0.
        let transcoder = TranscodeState::new().map_err(|e| format!("codec init: {e}"))?;
        let max_samples = max_duration_ms.map(|ms| (sample_rate as u64 * ms) / 1000);

        Ok(Self {
            writer,
            transcoder,
            source_pt: 0,
            total_samples: 0,
            sample_rate,
            max_samples,
            file_path: file_path.to_string(),
        })
    }

    /// Write raw PCM samples directly (no RTP decoding).
    /// Returns true if recording should continue, false if max duration reached.
    pub fn write_pcm(&mut self, samples: &[i16]) -> bool {
        for &sample in samples {
            if self.writer.write_sample(sample).is_err() {
                return false;
            }
            self.total_samples += 1;
            if let Some(max) = self.max_samples {
                if self.total_samples >= max {
                    return false;
                }
            }
        }
        true
    }

    /// Process an incoming RTP packet (full packet with header).
    /// Returns true if recording should continue, false if max duration reached.
    pub fn process_rtp(&mut self, data: &[u8]) -> bool {
        if data.len() <= 12 {
            return true; // Too short, skip.
        }

        let pt = data[1] & 0x7F;
        // Skip telephone-event (DTMF) packets.
        if pt == 101 {
            return true;
        }

        let payload = &data[12..];
        if payload.is_empty() {
            return true;
        }

        // Decode to PCM.
        let (pcm, rate) = match self.transcoder.decode_to_pcm(payload, self.source_pt) {
            Ok(result) => result,
            Err(_) => return true, // Decode failed, skip packet.
        };

        // Resample to 8kHz if needed.
        let pcm_8k = if rate != self.sample_rate {
            match self.transcoder.resample(&pcm, rate, self.sample_rate) {
                Ok(r) => r,
                Err(_) => return true,
            }
        } else {
            pcm
        };

        // Write samples.
        for &sample in &pcm_8k {
            if let Err(_) = self.writer.write_sample(sample) {
                return false;
            }
            self.total_samples += 1;

            if let Some(max) = self.max_samples {
                if self.total_samples >= max {
                    return false; // Max duration reached.
                }
            }
        }

        true
    }

    /// Stop recording and finalize the WAV file.
    pub fn stop(self) -> RecordingResult {
        let duration_ms = if self.sample_rate > 0 {
            (self.total_samples * 1000) / self.sample_rate as u64
        } else {
            0
        };

        // Writer is finalized on drop (writes RIFF header sizes).
        drop(self.writer);

        RecordingResult {
            file_path: self.file_path,
            duration_ms,
            total_samples: self.total_samples,
        }
    }
}

pub struct RecordingResult {
    pub file_path: String,
    pub duration_ms: u64,
    // Running-sample total kept for parity with the TS recorder; not yet
    // surfaced through any event or dashboard field.
    #[allow(dead_code)]
    pub total_samples: u64,
}
