use dupliter::{relativistic_to_classical_ratio, dupliter_stability_index, verdict};
use std::io::{self, Write};

const RESET: &str = "\x1b[0m";
const BOLD:  &str = "\x1b[1m";
fn fg(n: u8) -> String { format!("\x1b[38;5;{}m", n) }
fn clear() { print!("\x1b[2J\x1b[H"); }
fn divider() { println!("{}{}{}", fg(238), "─".repeat(80), RESET); }
fn headline(text: &str) {
    let pad = 80usize.saturating_sub(text.len()) / 2;
    println!("{}{}{}{}{}", fg(81), BOLD, " ".repeat(pad), text, RESET);
}

const JUPITER: &str = "
                 .-''-. 
              .-'  .---.  `-.
             /   .'     `.   \\
            /   /  .-\"-.-. \\   \\
           ;   ;  /  .-.  \\;    ;
           |   | |  /   \\  ||   |
           ;   ; | | .-. | ;'   ;
            \\   \\ \\ `-' / /   /
             `.  `.` `.'.  .' .'
               `-._`---'_.-'
                    `---'
";

fn prompt_float(label: &str, default: f64, min: f64, max: f64) -> f64 {
    loop {
        print!("{}{}{} ", fg(250), label, RESET);
        io::stdout().flush().unwrap();
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        let t = buf.trim();
        if t.is_empty() { return default; }
        match t.parse::<f64>() {
            Ok(v) if v < min => println!("{}Value too small (min {}).{}", fg(196), min, RESET),
            Ok(v) if v > max => println!("{}Value too large (max {}).{}", fg(196), max, RESET),
            Ok(v) => return v,
            Err(_) => println!("{}Please enter a valid number.{}", fg(208), RESET),
        }
    }
}

fn main() {
    clear();
    let g = fg(220);
    println!("{}{} ____  _   _  _     _ _ _  _   _  ___  _   _  _____ {}", g, BOLD, RESET);
    println!("{}{}|  _ \\| | | || |   (_) | \\| | | |/ _ \\| \\ | ||_   _|{}", g, BOLD, RESET);
    println!("{}{}| | | | |_| || |    _| | .` | | | | | |  \\| |  | |  {}", g, BOLD, RESET);
    println!("{}{}| |_| |  _  || |___| | | |\\  |_| | |_| | |\\  |  | |  {}", g, BOLD, RESET);
    println!("{}{}|____/|_| |_||_____|_|_|_| \\_(_) |\\___/|_| \\_|  |_|  {}", g, BOLD, RESET);
    println!("{}{}{}", fg(244), JUPITER, RESET);
    println!("Connecting to DUPliter Node... BBS handshake engaged.");
    println!("Transmitting the Dupliter hypothesis — a gravitational temporal anchor.");
    println!("Educational/exploratory. DSI is a comparative metric.\n");
    headline("DUPliter INTERACTIVE TERMINAL  v0.1.0  (Rust)");
    println!();

    loop {
        println!("{}{}Enter parameters (Enter = default):{}", fg(153), BOLD, RESET);
        let beta   = prompt_float("beta v/c (0..0.9999) [default 0.1]:", 0.1, 0.0, 0.9999);
        let dm     = prompt_float("Dark-matter potential (0..1e6) [default 1.0]:", 1.0, 0.0, 1e6);
        let anchor = prompt_float("Gravitational anchor (0..1e6) [default 1.0]:", 1.0, 0.0, 1e6);
        println!();

        let ratio = relativistic_to_classical_ratio(beta);
        let dsi   = dupliter_stability_index(ratio, dm, anchor, 0.01);
        let (level, message) = verdict(dsi);
        let colour = match level { "High" => fg(82), "Moderate" => fg(226), "Low" => fg(208), _ => fg(196) };

        divider();
        println!("{}{}Computed metrics:{}", fg(39), BOLD, RESET);
        println!("  beta (v/c)                       : {}{:.6}{}", fg(153), beta,  RESET);
        println!("  Relativistic / Classical KE ratio: {}{:.6}{}", fg(153), ratio, RESET);
        println!("  Dupliter Stability Index (DSI)   : {}{:.4}{}  [{}]", fg(153), dsi, RESET, level);
        println!("  Assessment                       : {}{}{}", colour, message, RESET);
        println!("\n{}  Equation: 2*(1/sqrt(1-b^2) - 1) / b^2   where b = v/c{}", fg(244), RESET);
        divider();
        println!();

        print!("{}Run another simulation? (Y/n): {}", fg(250), RESET);
        io::stdout().flush().unwrap();
        let mut ans = String::new();
        io::stdin().read_line(&mut ans).unwrap();
        if matches!(ans.trim().to_lowercase().as_str(), "n" | "no") {
            println!("{}Disconnecting from DUPliter Node. Keep hypothesizing.{}", fg(245), RESET);
            break;
        }
        println!();
    }
}
