use crate::cli::{err, hint, DEFAULT_PORT};
use anyhow::Result;
use clap::Parser;
use colored::Colorize;
use std::time::Duration;

#[derive(Parser)]
pub struct Args {
    /// Follow mode — keep polling and print new messages.
    #[arg(short, long)]
    pub follow: bool,

    #[arg(long, default_value_t = 0)]
    pub since: u64,

    #[arg(long, default_value_t = 50)]
    pub tail: usize,

    /// Comma-separated levels: log,warn,error.
    #[arg(long)]
    pub level: Option<String>,

    #[arg(long, default_value_t = DEFAULT_PORT)]
    pub port: u16,
}

pub fn run(args: Args) -> Result<()> {
    let level_filter: Option<Vec<String>> = args
        .level
        .as_deref()
        .map(|s| s.split(',').map(|x| x.trim().to_lowercase()).collect());
    let mut since = args.since;
    let mut first = true;
    loop {
        let url = format!("http://127.0.0.1:{}/console?since={}", args.port, since);
        let resp = match ureq::get(&url).timeout(Duration::from_secs(2)).call() {
            Ok(r) => r.into_json::<serde_json::Value>()?,
            Err(e) => {
                err(format!("could not reach adom-chipsmith: {e}"));
                hint("start it first with `adom-chipsmith view <file.step>`");
                return Err(anyhow::anyhow!("unreachable"));
            }
        };
        let next = resp
            .get("next_since")
            .and_then(|v| v.as_u64())
            .unwrap_or(since);
        let empty = vec![];
        let msgs = resp
            .get("messages")
            .and_then(|v| v.as_array())
            .unwrap_or(&empty);
        let slice: Vec<&serde_json::Value> = if first && msgs.len() > args.tail {
            msgs.iter().skip(msgs.len() - args.tail).collect()
        } else {
            msgs.iter().collect()
        };
        for m in slice {
            let lvl = m.get("level").and_then(|v| v.as_str()).unwrap_or("log");
            if let Some(filter) = &level_filter {
                if !filter.contains(&lvl.to_string()) {
                    continue;
                }
            }
            let seq = m.get("seq").and_then(|v| v.as_u64()).unwrap_or(0);
            let ts = m.get("ts_ms").and_then(|v| v.as_u64()).unwrap_or(0);
            let text = m.get("text").and_then(|v| v.as_str()).unwrap_or("");
            let ts_s = format!("{}.{:03}", ts / 1000, ts % 1000);
            let tag = match lvl {
                "error" => "ERR".red().bold().to_string(),
                "warn" => "WRN".yellow().bold().to_string(),
                _ => "LOG".cyan().bold().to_string(),
            };
            println!("[{:>6}] {} {} {}", seq, ts_s.dimmed(), tag, text);
        }
        since = next;
        first = false;
        if !args.follow {
            break;
        }
        std::thread::sleep(Duration::from_millis(400));
    }
    Ok(())
}