use super::{Lens, LensContext, LensId, LensOutput};
use forge::budget::estimator::TokenEstimator;
use once_cell::sync::Lazy;
use regex::Regex;

static NOISE_PATTERNS: Lazy<Vec<Regex>> = Lazy::new(|| {
    vec![
        Regex::new(r"^\s*$").unwrap(),                    // blank lines
        Regex::new(r"^={5,}$").unwrap(),                  // ==== separators
        Regex::new(r"^-{5,}$").unwrap(),                  // ---- separators
        Regex::new(r"^\s*#\s*$").unwrap(),                // lone comment
        Regex::new(r"^\s*Compiling .+ v[\d.]+").unwrap(), // cargo compiling spam
        Regex::new(r"^\s*Downloading\s").unwrap(),        // download noise
        Regex::new(r"^\s*Resolving\s").unwrap(),
    ]
});

/// Focus: remove known-noisy lines, keep task-relevant content.
pub struct FocusLens;

impl Lens for FocusLens {
    fn id(&self) -> LensId {
        LensId::Focus
    }

    fn apply(&self, input: &str, ctx: &LensContext) -> LensOutput {
        let tokens_before = TokenEstimator::count_nonblocking(input);

        let filtered: Vec<&str> = input
            .lines()
            .filter(|line| !NOISE_PATTERNS.iter().any(|re| re.is_match(line)))
            .collect();

        // If a task hint is provided, boost lines containing task keywords
        let content = if let Some(ref hint) = ctx.task_hint {
            let keywords: Vec<&str> = hint.split_whitespace().collect();
            let mut boosted: Vec<&str> = Vec::new();
            let mut rest: Vec<&str> = Vec::new();

            for line in &filtered {
                if keywords
                    .iter()
                    .any(|kw| line.to_lowercase().contains(&kw.to_lowercase()))
                {
                    boosted.push(line);
                } else {
                    rest.push(line);
                }
            }
            boosted.extend(rest);
            boosted.join("\n")
        } else {
            filtered.join("\n")
        };

        let tokens_after = TokenEstimator::count_nonblocking(&content);
        LensOutput {
            content,
            tokens_before,
            tokens_after,
            applied: vec!["focus".into()],
        }
    }
}
