use std::{fs::File, path::PathBuf};

use berblom::{graph::FlowGraph, tracing::install_tracing};
use clap::{Parser, ValueEnum};
use color_eyre::Result;
use wot_network::search::TrustAnchor;
use wot_search_tests::test_files::{TestCase, get_flow_test_case};

#[derive(Parser, ValueEnum, Debug, Clone, PartialEq, Eq)]
#[clap(rename_all = "snake_case")]
pub enum TestCaseCliOption {
    Cycle,
    DelegationsA,
    DelegationsAb,
    DelegationsB,
    Fulkerson,
    XwingAb,
}

impl From<TestCaseCliOption> for TestCase {
    fn from(opt: TestCaseCliOption) -> Self {
        match opt {
            TestCaseCliOption::Cycle => TestCase::Cycle,
            TestCaseCliOption::DelegationsA => TestCase::DelegationsA,
            TestCaseCliOption::DelegationsAb => TestCase::DelegationsAb,
            TestCaseCliOption::DelegationsB => TestCase::DelegationsB,
            TestCaseCliOption::Fulkerson => TestCase::Fulkerson,
            TestCaseCliOption::XwingAb => TestCase::XwingAb,
        }
    }
}

/// Debug binary to run specific test cases of the wot-search-tests crate for visualization and
/// debugging.
#[derive(Parser, Debug)]
#[clap(
    name = "run_test",
    about = "Run and visualize specific test cases from the wot-search-tests crate for debugging purposes."
)]
pub struct Cli {
    /// Select the test case to run.
    #[clap(value_enum)]
    pub test_case: TestCaseCliOption,

    /// The path to write the debug output to.
    #[clap(short, long, default_value = "./search_output.md")]
    pub output: PathBuf,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();
    install_tracing(3)?;

    // Get the test case
    let (network, test_case) = get_flow_test_case(cli.test_case.into());

    // Load the trust anchors of the test case
    let trust_anchors: Vec<_> = test_case
        .anchors
        .iter()
        .map(|anchor| TrustAnchor::new((&anchor.name).into(), anchor.amount))
        .collect();

    // Load the target binding
    let target_binding = wot_network::Binding {
        cert: (&test_case.lookups[0].cert).into(),
        identity: (&test_case.lookups[0].id).into(),
    };

    // Run the algorithm
    let mut graph = FlowGraph::new(network, trust_anchors, target_binding);
    let mut file = if cli.output.exists() {
        File::options().write(true).open(cli.output)?
    } else {
        File::create(cli.output)?
    };
    let _paths = graph.search_with_mermaid(None, &mut file)?;

    Ok(())
}
