//! v4.2 c3 — dogfood usecase: G9 capability close real-sim regression.
//!
//! End-to-end proves the G9 system-popup-action wire chain by enumerating
//! the insight logout confirm dialog and dispatching the affirmative
//! button through `App::system_popup_action(popup_id, button_id)`. The
//! same dialog is dismissed in `insight_dogfood_auth_logout.rs` via the
//! pre-G9 workaround (`App::tap(&text("Log out"))`) — this example
//! exercises the new wire instead.
//!
//! Flow:
//! 1. launch_fresh — terminate + open_url + reach landing (logout if
//!    a prior session was authenticated).
//! 2. login_form — 3-step form (E2E_EMAIL / E2E_ORG / E2E_PASSWORD) →
//!    home screen with `btn-open-menu` visible.
//! 3. open drawer → scroll until "Log out" → tap "Log out" — surfaces
//!    the in-app confirm dialog.
//! 4. `App::system_popups()` — enumerate the on-screen popup set;
//!    expect ≥ 1 popup whose buttons include a label "Log out".
//! 5. `App::system_popup_action(popup_id, button_id)` — dispatch tap on
//!    the "Log out" affirmative button via the v4.2 c1 swift route +
//!    UITest daemonProxy synthesize chain.
//! 6. Assert landing screen visible ⇒ G9 wire end-to-end ✅.
//!
//! Same SMIX_UDID / SMIX_E2E_* / TEST_RUNNER_SMIX_RUNNER_TARGET_BUNDLE
//! env vars as the v3.17 c2 auth dogfoods. Net-mutation: ends logged out.

use smix_sdk::{
    App, ExpectationFailure, FailureInit, KeyName, SwipeDirection, TapMode, id, text, text_regex,
};
use std::time::Duration;

#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let port: u16 = std::env::var("SMIX_RUNNER_PORT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(22087);
    let udid = std::env::var("SMIX_UDID").ok();

    println!("smix dogfood — G9 system-popup-action (v4.2 c3)");
    println!("===============================================");
    println!("runner port: {port}");
    println!("udid:        {:?}", udid);
    println!();

    let mut app = App::connect_to_runner(port).await?;
    if let Some(u) = udid {
        app = app.with_udid(u);
    }

    let bundle_id =
        std::env::var("INSIGHT_BUNDLE_ID").unwrap_or_else(|_| "com.focusai.app.mobile".to_string());

    println!("launch_fresh: starting");
    launch_fresh(&app, &bundle_id).await?;
    println!("launch_fresh: done\n");

    match g9_popup_action_flow(&app).await {
        Ok(()) => {
            println!("\n✓ G9 popup-action flow passed (1-round dogfood)");
            println!("\n🎉 v4.2 c3 dogfood — G9 system-popup-action ✅");
            Ok(())
        }
        Err(e) => {
            println!("\n✗ G9 popup-action flow failed");
            for line in e.to_prompt().lines() {
                println!("    {line}");
            }
            Err("dogfood G9 popup-action FAIL".into())
        }
    }
}

async fn launch_fresh(app: &App, bundle_id: &str) -> Result<(), ExpectationFailure> {
    println!("  launch-fresh: terminate + openurl + handle logged-in (logout if needed)");
    let _ = app.terminate(bundle_id).await;
    tokio::time::sleep(Duration::from_millis(800)).await;
    app.open_url("exp+focus-ai-app://expo-development-client/?url=http%3A%2F%2Flocalhost%3A8081")
        .await?;
    app.wait_for(
        &text_regex("Log in to Insight|Open menu|Device"),
        Duration::from_secs(30),
    )
    .await?;

    if app.find(&id("btn-open-menu")).await? {
        println!("  already logged in, perform logout to reach landing");

        for _ in 0..5 {
            if app
                .wait_for(&text("Dashboard"), Duration::from_millis(500))
                .await
                .is_ok()
            {
                break;
            }
            let _ = app.tap(&text("Open menu")).await;
            tokio::time::sleep(Duration::from_millis(800)).await;
        }

        for _ in 0..10 {
            if app.find(&text("Log out")).await? {
                break;
            }
            app.scroll(&text("Log out"), SwipeDirection::Up).await?;
            tokio::time::sleep(Duration::from_millis(400)).await;
        }

        app.tap(&text("Log out")).await?;
        tokio::time::sleep(Duration::from_millis(1500)).await;
        if app.find(&text("Cancel")).await? {
            println!("  logout confirm dialog detected, tap 'Log out' to confirm");
            app.tap(&text("Log out")).await?;
        }
        app.wait_for(&text("Log in to Insight"), Duration::from_secs(30))
            .await?;
    }

    tokio::time::sleep(Duration::from_secs(2)).await;
    Ok(())
}

async fn login_form(app: &App) -> Result<(), ExpectationFailure> {
    let email = std::env::var("SMIX_E2E_EMAIL")
        .or_else(|_| std::env::var("E2E_EMAIL"))
        .map_err(|_| {
            ExpectationFailure::new(FailureInit {
                message: "login_form: E2E_EMAIL env var is required but unset".into(),
                ..Default::default()
            })
        })?;
    let org = std::env::var("SMIX_E2E_ORG")
        .or_else(|_| std::env::var("E2E_ORG"))
        .map_err(|_| {
            ExpectationFailure::new(FailureInit {
                message: "login_form: E2E_ORG env var is required but unset".into(),
                ..Default::default()
            })
        })?;
    let password = std::env::var("SMIX_E2E_PASSWORD")
        .or_else(|_| std::env::var("E2E_PASSWORD"))
        .map_err(|_| {
            ExpectationFailure::new(FailureInit {
                message: "login_form: E2E_PASSWORD env var is required but unset".into(),
                ..Default::default()
            })
        })?;

    println!("  login_form: landing → sign-in (G8 daemonProxy)");
    app.tap_with_mode(&text("Log in to Insight"), TapMode::DaemonProxySynthesize)
        .await?;
    app.wait_for(&id("input-email"), Duration::from_secs(10))
        .await?;

    println!("  login_form: step 1 email");
    app.tap(&id("input-email")).await?;
    app.clear(&id("input-email")).await?;
    app.fill(&id("input-email"), &email).await?;
    app.press_key(KeyName::Return).await?;
    app.tap(&text("Continue")).await?;
    app.wait_for(
        &text_regex("Enter new organization|Organization name"),
        Duration::from_secs(10),
    )
    .await?;

    println!("  login_form: step 2 org");
    if app.find(&text("Enter new organization")).await? {
        app.tap(&text("Enter new organization")).await?;
        tokio::time::sleep(Duration::from_millis(400)).await;
    }
    app.tap(&id("input-org")).await?;
    app.clear(&id("input-org")).await?;
    app.fill(&id("input-org"), &org).await?;
    app.press_key(KeyName::Return).await?;
    app.tap(&text("Continue")).await?;
    app.wait_for(&id("input-password"), Duration::from_secs(10))
        .await?;

    // step 3: password — direct fill secureTextEntry (smix fill works, no toggle)
    println!("  login_form: step 3 password");
    tokio::time::sleep(Duration::from_millis(400)).await;
    app.tap(&id("input-password")).await?;
    app.fill(&id("input-password"), &password).await?;
    app.hide_keyboard().await?;
    app.tap(&id("btn-login")).await?;
    app.wait_for(&id("btn-open-menu"), Duration::from_secs(30))
        .await?;
    Ok(())
}

async fn g9_popup_action_flow(app: &App) -> Result<(), ExpectationFailure> {
    println!("step 1: launch_fresh already executed; landing expected");

    println!("step 2: login_form (E2E_EMAIL / E2E_ORG / E2E_PASSWORD)");
    login_form(app).await?;

    println!("step 3: open drawer + scroll until 'Log out' visible");
    tokio::time::sleep(Duration::from_millis(800)).await;
    app.wait_for(&id("btn-open-menu"), Duration::from_secs(30))
        .await?;
    for _ in 0..5 {
        if app
            .wait_for(&text("Dashboard"), Duration::from_millis(500))
            .await
            .is_ok()
        {
            break;
        }
        let _ = app.tap(&text("Open menu")).await;
        tokio::time::sleep(Duration::from_millis(800)).await;
    }
    for _ in 0..10 {
        if app.find(&text("Log out")).await? {
            break;
        }
        app.scroll(&text("Log out"), SwipeDirection::Up).await?;
        tokio::time::sleep(Duration::from_millis(400)).await;
    }

    println!("step 4: tap drawer 'Log out' (RN-side text button) → surfaces confirm dialog");
    app.tap(&text("Log out")).await?;
    tokio::time::sleep(Duration::from_millis(1500)).await;

    println!("step 5: enumerate via App::system_popups() — expect 1 popup with 'Log out' button");
    let popups = app.system_popups().await?;
    if popups.is_empty() {
        return Err(ExpectationFailure::new(FailureInit {
            message: "system_popups() returned empty after tapping drawer 'Log out'; expected 1 in-app confirm dialog".into(),
            ..Default::default()
        }));
    }
    // Pick the first popup with a button labeled "Log out" (case-sensitive
    // match against the popup-button label field surfaced by the runner).
    let mut chosen: Option<(String, String)> = None;
    for p in &popups {
        for b in &p.buttons {
            if b.label == "Log out" {
                chosen = Some((p.id.clone(), b.id.clone()));
                break;
            }
        }
        if chosen.is_some() {
            break;
        }
    }
    let (popup_id, button_id) = chosen.ok_or_else(|| {
        ExpectationFailure::new(FailureInit {
            message: format!(
                "no popup with 'Log out' button in {} enumerated popups; first popup buttons = {:?}",
                popups.len(),
                popups
                    .first()
                    .map(|p| p.buttons.iter().map(|b| b.label.clone()).collect::<Vec<_>>())
                    .unwrap_or_default()
            ),
            ..Default::default()
        })
    })?;
    println!("  matched popup_id={popup_id} button_id={button_id}");

    println!("step 6: App::system_popup_action(popup_id, button_id) — G9 wire dispatch");
    let ok = app.system_popup_action(&popup_id, &button_id).await?;
    if !ok {
        return Err(ExpectationFailure::new(FailureInit {
            message: format!(
                "system_popup_action({popup_id}, {button_id}) returned Ok(false) — runner reported not_found; popup may have closed mid-dispatch"
            ),
            ..Default::default()
        }));
    }

    println!("step 7: assert landing screen visible (logout completed via G9)");
    app.wait_for(&text("Log in to Insight"), Duration::from_secs(30))
        .await?;
    Ok(())
}
