//! Storage module for persisting recording history.

use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
use thiserror::Error;
use tracing::{debug, info, warn};

#[derive(Error, Debug)]
pub enum StorageError {
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    #[error("Serialization error: {0}")]
    SerializationError(#[from] serde_json::Error),
    #[error("Recording not found: {0}")]
    RecordingNotFound(String),
}

/// A transcript segment with timing information.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoredTranscriptSegment {
    pub start: f64,
    pub end: f64,
    pub text: String,
    pub speaker: String,
}

/// A stored recording with all its data.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoredRecording {
    pub id: String,
    pub timestamp: String, // ISO 8601 timestamp
    pub duration: f64,
    pub transcript_segments: Vec<StoredTranscriptSegment>,
    pub summary: Option<String>,
    pub title: Option<String>,
}

/// Storage manager for recordings.
pub struct RecordingStorage {
    storage_dir: PathBuf,
}

impl RecordingStorage {
    /// Create a new storage manager.
    pub fn new(app_data_dir: &Path) -> Result<Self, StorageError> {
        let storage_dir = app_data_dir.join("recordings");

        // Ensure the directory exists
        fs::create_dir_all(&storage_dir)?;

        info!("Recording storage initialized at: {}", storage_dir.display());

        Ok(Self { storage_dir })
    }

    /// Save a recording to disk.
    pub fn save_recording(&self, recording: &StoredRecording) -> Result<(), StorageError> {
        let file_path = self.storage_dir.join(format!("{}.json", recording.id));

        debug!("Saving recording {} to {}", recording.id, file_path.display());

        let json_data = serde_json::to_string_pretty(recording)?;
        fs::write(&file_path, json_data)?;

        info!("Recording {} saved successfully", recording.id);
        Ok(())
    }

    /// Load all recordings from disk.
    pub fn load_all_recordings(&self) -> Result<Vec<StoredRecording>, StorageError> {
        let mut recordings = Vec::new();

        debug!("Loading recordings from {}", self.storage_dir.display());

        // Read all JSON files in the directory
        if let Ok(entries) = fs::read_dir(&self.storage_dir) {
            for entry in entries.flatten() {
                let path = entry.path();

                // Skip non-JSON files
                if path.extension().and_then(|s| s.to_str()) != Some("json") {
                    continue;
                }

                // Try to load the recording
                match fs::read_to_string(&path) {
                    Ok(contents) => {
                        match serde_json::from_str::<StoredRecording>(&contents) {
                            Ok(recording) => {
                                recordings.push(recording);
                            }
                            Err(e) => {
                                warn!("Failed to parse recording file {}: {}", path.display(), e);
                            }
                        }
                    }
                    Err(e) => {
                        warn!("Failed to read recording file {}: {}", path.display(), e);
                    }
                }
            }
        }

        // Sort by timestamp (newest first)
        recordings.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));

        info!("Loaded {} recordings", recordings.len());
        Ok(recordings)
    }

    /// Delete a specific recording.
    pub fn delete_recording(&self, recording_id: &str) -> Result<(), StorageError> {
        let file_path = self.storage_dir.join(format!("{}.json", recording_id));

        if !file_path.exists() {
            return Err(StorageError::RecordingNotFound(recording_id.to_string()));
        }

        debug!("Deleting recording {} at {}", recording_id, file_path.display());
        fs::remove_file(&file_path)?;

        info!("Recording {} deleted successfully", recording_id);
        Ok(())
    }

    /// Update an existing recording (e.g., to add summary).
    pub fn update_recording(&self, recording: &StoredRecording) -> Result<(), StorageError> {
        // For now, just overwrite the file
        self.save_recording(recording)
    }

    /// Check if a recording exists.
    pub fn recording_exists(&self, recording_id: &str) -> bool {
        let file_path = self.storage_dir.join(format!("{}.json", recording_id));
        file_path.exists()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;

    #[test]
    fn test_storage_operations() {
        let temp_dir = TempDir::new().unwrap();
        let storage = RecordingStorage::new(temp_dir.path()).unwrap();

        // Create a test recording
        let recording = StoredRecording {
            id: "test123".to_string(),
            timestamp: "2024-01-01T12:00:00Z".to_string(),
            duration: 60.0,
            transcript_segments: vec![
                StoredTranscriptSegment {
                    start: 0.0,
                    end: 5.0,
                    text: "Hello world".to_string(),
                    speaker: "Speaker 1".to_string(),
                },
            ],
            summary: Some("Test summary".to_string()),
            title: Some("Test Meeting".to_string()),
        };

        // Save it
        storage.save_recording(&recording).unwrap();
        assert!(storage.recording_exists("test123"));

        // Load it back
        let recordings = storage.load_all_recordings().unwrap();
        assert_eq!(recordings.len(), 1);
        assert_eq!(recordings[0].id, "test123");

        // Delete it
        storage.delete_recording("test123").unwrap();
        assert!(!storage.recording_exists("test123"));

        // Verify it's gone
        let recordings = storage.load_all_recordings().unwrap();
        assert_eq!(recordings.len(), 0);
    }
}