Documentation
use crate::error::{CliError, Result};
use glyph_core::{Frame, Glyph};
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

pub fn create_glyph(
    input_files: Vec<PathBuf>,
    output: PathBuf,
    default_duration: u32,
) -> Result<()> {
    // Read the first file to determine dimensions
    let mut first_content = String::new();
    File::open(&input_files[0])
        .map_err(|e| {
            CliError::File(format!(
                "Failed to open {}: {}",
                input_files[0].display(),
                e
            ))
        })?
        .read_to_string(&mut first_content)?;

    let lines: Vec<&str> = first_content.lines().collect();
    let height = lines.len() as u32;
    let width = lines.iter().map(|line| line.len()).max().unwrap_or(0) as u32;

    // Create new Glyph
    let mut glyph = Glyph::new(width, height, default_duration);

    // Add frames
    for path in input_files {
        let mut content = String::new();
        File::open(&path)
            .map_err(|e| CliError::File(format!("Failed to open {}: {}", path.display(), e)))?
            .read_to_string(&mut content)?;

        // Pad lines to match width if necessary
        let mut padded_content = String::new();
        for line in content.lines() {
            let padding = " ".repeat((width as usize).saturating_sub(line.len()));
            padded_content.push_str(line);
            padded_content.push_str(&padding);
            padded_content.push('\n');
        }

        // Pad height if necessary
        while padded_content.lines().count() < height as usize {
            padded_content.push_str(&" ".repeat(width as usize));
            padded_content.push('\n');
        }

        // Remove trailing newline if present
        if padded_content.ends_with('\n') {
            padded_content.pop();
        }

        let frame = Frame::new(padded_content);
        glyph.add_frame(frame).map_err(|e| {
            CliError::File(format!(
                "Failed to add frame from {}: {}",
                path.display(),
                e
            ))
        })?;
    }

    // Write to output file
    let mut output_file = File::create(&output).map_err(|e| {
        CliError::File(format!(
            "Failed to create output file {}: {}",
            output.display(),
            e
        ))
    })?;

    glyph
        .write(&mut output_file)
        .map_err(|e| CliError::File(format!("Failed to write Glyph file: {}", e)))?;

    println!("Created Glyph animation with {} frames", glyph.frames.len());
    Ok(())
}

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

    fn create_test_file(dir: &TempDir, name: &str, content: &str) -> PathBuf {
        let path = dir.path().join(name);
        let mut file = File::create(&path).unwrap();
        writeln!(file, "{}", content).unwrap();
        path
    }

    #[test]
    fn test_create_single_frame() {
        let temp_dir = TempDir::new().unwrap();
        let input = create_test_file(&temp_dir, "frame1.txt", "abc\ndef");
        let output = temp_dir.path().join("output.glyph");

        create_glyph(vec![input], output.clone(), 100).unwrap();

        // Verify the output file exists and can be read as a valid glyph
        let mut file = File::open(output).unwrap();
        let glyph = Glyph::read(&mut file).unwrap();
        assert_eq!(glyph.frames.len(), 1);
        assert_eq!(glyph.frames[0].content, "abc\ndef");
    }

    #[test]
    fn test_create_multiple_frames() {
        let temp_dir = TempDir::new().unwrap();
        let input1 = create_test_file(&temp_dir, "frame1.txt", "abc\ndef");
        let input2 = create_test_file(&temp_dir, "frame2.txt", "ABC\nDEF");
        let output = temp_dir.path().join("output.glyph");

        create_glyph(vec![input1, input2], output.clone(), 100).unwrap();

        let mut file = File::open(output).unwrap();
        let glyph = Glyph::read(&mut file).unwrap();
        assert_eq!(glyph.frames.len(), 2);
        assert_eq!(glyph.frames[0].content, "abc\ndef");
        assert_eq!(glyph.frames[1].content, "ABC\nDEF");
    }

    #[test]
    fn test_create_with_padding() {
        let temp_dir = TempDir::new().unwrap();
        let input1 = create_test_file(&temp_dir, "frame1.txt", "abcd\nefgh"); // 4x2
        let input2 = create_test_file(&temp_dir, "frame2.txt", "ab\nef"); // 2x2
        let output = temp_dir.path().join("output.glyph");

        create_glyph(vec![input1, input2], output.clone(), 100).unwrap();

        let mut file = File::open(output).unwrap();
        let glyph = Glyph::read(&mut file).unwrap();
        assert_eq!(glyph.frames.len(), 2);
        assert_eq!(glyph.frames[0].content, "abcd\nefgh");
        assert_eq!(glyph.frames[1].content, "ab  \nef  "); // Padded with spaces
    }

    #[test]
    fn test_create_with_invalid_input() {
        let temp_dir = TempDir::new().unwrap();
        let output = temp_dir.path().join("output.glyph");

        // Test with non-existent file
        let result = create_glyph(vec![PathBuf::from("nonexistent.txt")], output.clone(), 100);
        assert!(result.is_err());
    }
}