//! Run test suite of a project repeatedly, to find flaky tests that
//! only sometimes fail.
//!
//! It is surprisingly easy to accidentally implement an automated
//! test so that it sometimes fails. This might be, for example, when
//! there is a race condition in the test, or in the code under test.
//! The wumpus hunter helps find such tests, by running them
//! repeatedly.
//!
//! The wumpus hunter is configured to run a test command for a given
//! git repository and branch in that repository. It clones the
//! repository, and pulls updates, and runs the command, either for a
//! given number of times, or indefinitely.
//!
//! The wumpus hunter is primarily a command line program, but is
//! exposed also as a library in the hope it can be useful for
//! building other useful tools.

#![deny(missing_docs)]

use std::{path::PathBuf, time::SystemTime};

use radicle::git::Oid;

use clap::Parser;
use time::{macros::format_description, OffsetDateTime};

pub mod report;
pub mod run;
pub(crate) mod runlog;
pub mod spec;

const CSS: &str = include_str!("wumpus.css");
const STATS_TXT: &str = "stats.txt";
const SUCCESS: &str = "SUCCESS";
const FAILURE: &str = "FAILURE";

/// The command line arguments for the wumpus hunter.
#[derive(Debug, Parser)]
#[clap(version)]
pub struct Args {
    /// The sub-command.
    #[clap(subcommand)]
    pub cmd: Cmd,
}

/// The sub-commands for the wumpus hunter.
#[derive(Debug, Parser)]
#[allow(missing_docs)]
pub enum Cmd {
    Run(run::Run),
    Report(ReportCmd),
    DummyLog(DummyLog),
}

/// Sub-command to produce a dummy HTML report.
///
/// This is only useful for testing changes to the wumpus hunter
/// report generation.
#[derive(Debug, Parser)]
pub struct ReportCmd {
    stats: PathBuf,
    spec: PathBuf,
    git: PathBuf,
}

impl ReportCmd {
    /// Run the `report` sub-command.
    pub fn run(&self) -> anyhow::Result<()> {
        let spec = spec::Spec::from_file(&self.spec)?;
        let report = report::Report::new(&spec.description, &self.stats)?;
        print!("{}", report.as_html(&spec, &self.git));
        Ok(())
    }
}

pub(crate) fn timestamp(when: &SystemTime) -> String {
    let fmt = format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z");
    OffsetDateTime::from(*when).format(fmt).ok().unwrap()
}

/// Sub-command to produce a dummy HTML run log.
///
/// This is only useful for testing changes to the wumpus hunter
/// report generation.
#[derive(Debug, Parser)]
pub struct DummyLog {}

impl DummyLog {
    /// Run the `report` sub-command.
    pub fn run(&self) {
        let mut run_log = runlog::RunLog::default();
        run_log.url("https://liw.fi");
        run_log.git_ref("master");
        run_log.git_commit(Oid::try_from("06f52d8a538e79b09bd8252a1346542ed179cd60").unwrap());
        run_log.runcmd(
            &["git", "clean", "-fdx"],
            0,
            "This is stdout",
            "This is stderr",
        );
        println!("{}", run_log.as_html());
    }
}
