//! Ignored real-Chrome smoke tests for the browser tool.
//!
//! Run locally (requires Chrome/Chromium installed):
//! ```bash
//! cargo test --features browser browser_smoke_real_chrome -- --ignored --nocapture
//! ```

use std::time::Duration;

use serde_json::json;
use tempfile::TempDir;
use tokio::sync::mpsc;

use crate::config::BrowserConfig;
use crate::tools::terminal::ApprovalRequest;
use crate::tools::{ApprovalBroker, BrowserTool};
use crate::traits::Tool;
use crate::types::ApprovalResponse;

fn auto_approve_broker() -> ApprovalBroker {
    let (tx, mut rx) = mpsc::channel::<ApprovalRequest>(8);
    tokio::spawn(async move {
        while let Some(req) = rx.recv().await {
            let _ = req.response_tx.send(ApprovalResponse::AllowSession);
        }
    });
    ApprovalBroker::new(tx)
}

fn smoke_browser_config(user_data_dir: &str) -> BrowserConfig {
    BrowserConfig {
        enabled: true,
        headless: true,
        user_data_dir: Some(user_data_dir.to_string()),
        session_isolation: Some(crate::config::SessionIsolation::BrowserContext),
        ..BrowserConfig::default()
    }
}

fn write_smoke_fixture(dir: &TempDir) -> String {
    let path = dir.path().join("page.html");
    std::fs::write(
        &path,
        r#"<!DOCTYPE html>
<html><body>
<input id="name" type="text" value="old">
<button id="go" type="button">Go</button>
<div id="out">hello smoke</div>
<script>
  document.getElementById('go').addEventListener('click', function() {
    document.getElementById('name').value = 'new';
    document.getElementById('out').textContent = 'clicked';
  });
  console.error('smoke-console-error');
</script>
</body></html>"#,
    )
    .expect("write fixture");
    format!("file://{}", path.display())
}

#[tokio::test]
#[ignore = "requires local Chrome; run with --ignored"]
async fn browser_smoke_real_chrome() {
    let profile = TempDir::new().expect("temp profile");
    let fixture = TempDir::new().expect("temp fixture");
    let fixture_url = write_smoke_fixture(&fixture);

    let (media_tx, _media_rx) = mpsc::channel(4);
    let tool = BrowserTool::new(
        smoke_browser_config(profile.path().to_str().unwrap()),
        media_tx,
        auto_approve_broker(),
        profile.path().join("inbox"),
    )
    .expect("construct browser tool");

    let session = "smoke-session";

    let nav = tool
        .call(
            &json!({
                "action": "navigate",
                "url": fixture_url,
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("navigate");
    assert!(nav.starts_with("Navigated to"), "navigate failed: {nav}");

    let fill = tool
        .call(
            &json!({
                "action": "fill",
                "selector": "#name",
                "value": "replaced",
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("fill");
    assert_eq!(fill, "Filled '#name'");

    let click = tool
        .call(
            &json!({
                "action": "click",
                "selector": "#go",
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("click");
    assert!(click.contains("Clicked element '#go'"), "{click}");

    tokio::time::sleep(Duration::from_millis(300)).await;

    let text = tool
        .call(
            &json!({
                "action": "get_text",
                "selector": "#out",
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("get_text");
    assert!(
        text.contains("clicked"),
        "expected post-click text, got: {text}"
    );

    let logs = tool
        .call(
            &json!({
                "action": "get_console_logs",
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("get_console_logs");
    assert!(
        logs.contains("smoke-console-error") || logs.contains("Console logs"),
        "expected console capture, got: {logs}"
    );

    let shot = tool
        .call(
            &json!({
                "action": "screenshot",
                "_session_id": session
            })
            .to_string(),
        )
        .await
        .expect("screenshot");
    assert!(
        shot.contains("Screenshot captured"),
        "screenshot failed: {shot}"
    );

    let close = tool
        .call(&json!({ "action": "close", "_session_id": session }).to_string())
        .await
        .expect("close");
    assert!(
        close.contains("closed") || close.contains("Closed"),
        "close message unexpected: {close}"
    );
}
