mod finance;
mod runtime;
mod validate;

use crate::app::command::{Command, parse_command};

pub(super) fn run() -> Result<(), Box<dyn std::error::Error>> {
    dispatch_command(parse_command()?)
}

fn dispatch_command(command: Command) -> Result<(), Box<dyn std::error::Error>> {
    match command {
        Command::Validate { repo_root } => validate::dispatch_validate(repo_root),
        Command::Finance(command) => finance::dispatch_finance(command),
        Command::Runtime(command) => runtime::dispatch_runtime(command),
    }
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::path::PathBuf;
    use std::time::{SystemTime, UNIX_EPOCH};

    use rrt_model::finance::FinanceSnapshot;

    use super::dispatch_command;
    use crate::app::command::{Command, FinanceCommand, FixtureStateCommand, RuntimeCommand};

    fn workspace_root() -> PathBuf {
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..")
    }

    fn unique_temp_path(stem: &str) -> PathBuf {
        let unique = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("system time should be after epoch")
            .as_nanos();
        std::env::temp_dir().join(format!("rrt-cli-{stem}-{unique}.json"))
    }

    #[test]
    fn dispatches_validate_command() {
        dispatch_command(Command::Validate {
            repo_root: workspace_root(),
        })
        .expect("validate dispatch should succeed");
    }

    #[test]
    fn dispatches_finance_eval_command() {
        let snapshot_path = unique_temp_path("finance-eval");
        let snapshot = FinanceSnapshot {
            policy: Default::default(),
            company: Default::default(),
        };
        fs::write(
            &snapshot_path,
            serde_json::to_vec_pretty(&snapshot).expect("snapshot should serialize"),
        )
        .expect("snapshot should be written");

        let result = dispatch_command(Command::Finance(FinanceCommand::Eval {
            snapshot_path: snapshot_path.clone(),
        }));
        let _ = fs::remove_file(&snapshot_path);

        result.expect("finance dispatch should succeed");
    }

    #[test]
    fn dispatches_runtime_fixture_state_command() {
        dispatch_command(Command::Runtime(RuntimeCommand::FixtureState(
            FixtureStateCommand::SummarizeState {
                snapshot_path: workspace_root()
                    .join("fixtures/runtime/minimal-world-state-input.json"),
            },
        )))
        .expect("runtime fixture/state dispatch should succeed");
    }
}
