// wasot-tools: Utility tools for Wasot
//
// Commands included:
// - random: Generate random Wasot file for testing
// - fast-random: Generate random Wasot file (optimized for extreme performance)
// - to-yaml-test: Convert Wasot to YAML test format

use clap::{Parser, Subcommand};
use std::io::{self, BufWriter, Read};
use std::process;
use wasot_compiler::events::events::Emitter;
use wasot_compiler::{
    Consumer, FastRandomEmitter, RandomEmitter, ToYamlTestConsumer, WasotFileEmitter,
    WasotReconstructor,
};

#[derive(Parser)]
#[command(name = "wasot-tools")]
#[command(about = "Utility tools for Wasot")]
#[command(version = "0.1.0")]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Generate a random Wasot file for testing purposes
    Random {
        /// Number of random events to generate
        #[arg(short = 'n', long, default_value = "100")]
        event_count: usize,

        /// Output file path (optional, writes to stdout if not provided)
        #[arg(short = 'o', long)]
        output: Option<String>,

        /// Random seed for reproducible output
        #[arg(short = 's', long)]
        seed: Option<u64>,
    },

    /// Generate a random Wasot file optimized for extreme performance (trillion+ events)
    FastRandom {
        /// Number of random events to generate
        #[arg(short = 'n', long, default_value = "100")]
        event_count: usize,

        /// Output file path (optional, writes to stdout if not provided)
        #[arg(short = 'o', long)]
        output: Option<String>,

        /// Random seed for reproducible output
        #[arg(short = 's', long)]
        seed: Option<u64>,
    },

    /// Convert a Wasot file to YAML test format (like in language_e2e.md)
    ToYamlTest {
        /// Path to the Wasot file to convert (optional, reads from stdin if not provided)
        file_path: Option<String>,
    },
}

fn process_random(
    event_count: usize,
    output: Option<&str>,
    seed: Option<u64>,
) -> Result<(), Box<dyn std::error::Error>> {
    let emitter = if let Some(seed) = seed {
        RandomEmitter::with_seed(event_count, seed)
    } else {
        RandomEmitter::new(event_count)
    };

    // Use bounded channel for memory safety
    use std::sync::mpsc;
    use std::thread;

    let (sender, receiver) = mpsc::sync_channel(1000);

    let emitter_handle = thread::spawn(move || {
        let events = emitter.subscribe();
        for event in events {
            if sender.send(event).is_err() {
                break;
            }
        }
    });

    match output {
        Some(file_path) => {
            let file = std::fs::File::create(file_path)?;
            let writer = BufWriter::new(file);
            let mut reconstructor = WasotReconstructor::new_with_writer(writer);

            for event in receiver {
                reconstructor.on_element_event(&event);
            }

            emitter_handle
                .join()
                .map_err(|_| "Emitter thread panicked")?;

            println!("Generated random Wasot file with {event_count} events to: {file_path}");
        }
        None => {
            let mut reconstructor = WasotReconstructor::new();

            for event in receiver {
                reconstructor.on_element_event(&event);
            }

            emitter_handle
                .join()
                .map_err(|_| "Emitter thread panicked")?;
        }
    }

    Ok(())
}

fn process_fast_random(
    event_count: usize,
    output: Option<&str>,
    seed: Option<u64>,
) -> Result<(), Box<dyn std::error::Error>> {
    let emitter = if let Some(seed) = seed {
        FastRandomEmitter::with_seed(event_count, seed)
    } else {
        FastRandomEmitter::new(event_count)
    };

    use std::sync::mpsc;
    use std::thread;
    let (sender, receiver) = mpsc::sync_channel(1000);

    let emitter_handle = thread::spawn(move || {
        let events = emitter.subscribe();
        for event in events {
            if sender.send(event).is_err() {
                break;
            }
        }
    });

    match output {
        Some(file_path) => {
            let file = std::fs::File::create(file_path)?;
            let writer = BufWriter::new(file);
            let mut reconstructor = WasotReconstructor::new_with_writer(writer);

            for event in receiver {
                reconstructor.on_element_event(&event);
            }

            emitter_handle
                .join()
                .map_err(|_| "Fast emitter thread panicked")?;
            println!("Generated fast random Wasot file with {event_count} events to: {file_path}");
        }
        None => {
            let mut reconstructor = WasotReconstructor::new();

            for event in receiver {
                reconstructor.on_element_event(&event);
            }

            emitter_handle
                .join()
                .map_err(|_| "Fast emitter thread panicked")?;
        }
    }

    Ok(())
}

fn process_to_yaml_test(file_path: Option<&str>) -> Result<(), Box<dyn std::error::Error>> {
    use std::thread;

    let emitter = match file_path {
        Some(path) => {
            use std::path::Path;
            if !Path::new(path).exists() {
                return Err(format!("File not found: {path}").into());
            }
            WasotFileEmitter::from_file(path)
        }
        None => {
            let mut buffer = String::new();
            io::stdin().read_to_string(&mut buffer)?;
            WasotFileEmitter::from_string(buffer)
        }
    };

    let receiver = emitter.subscribe();

    let emitter_handle = thread::spawn(move || {
        emitter.run();
    });

    let mut yaml_consumer = ToYamlTestConsumer::new();
    yaml_consumer.run(receiver);

    emitter_handle
        .join()
        .map_err(|_| "Emitter thread panicked")?;

    Ok(())
}

fn main() {
    let cli = Cli::parse();

    match &cli.command {
        Commands::Random {
            event_count,
            output,
            seed,
        } => {
            if let Err(err) = process_random(*event_count, output.as_deref(), *seed) {
                eprintln!("Error generating random Wasot file: {err}");
                process::exit(1);
            }
        }
        Commands::FastRandom {
            event_count,
            output,
            seed,
        } => {
            if let Err(err) = process_fast_random(*event_count, output.as_deref(), *seed) {
                eprintln!("Error generating fast random Wasot file: {err}");
                process::exit(1);
            }
        }
        Commands::ToYamlTest { file_path } => {
            if let Err(err) = process_to_yaml_test(file_path.as_deref()) {
                eprintln!("Error converting to YAML test format: {err}");
                process::exit(1);
            }
        }
    }
}
