use reqwest::Url;
use serde_json::{json, Value};
use thiserror::Error;

use crate::config::PlannerMode;
use crate::pipe::Action;

/// Legacy deterministic planner kept for dev-only verification and fixture coverage.
/// Production browser submit flow no longer routes into this planner.
pub const LEGACY_DEV_ONLY: bool = true;

const BAIDU_URL: &str = "https://www.baidu.com";
const BAIDU_DOMAIN: &str = "www.baidu.com";
const BAIDU_INPUT_SELECTOR: &str = "#kw";
const BAIDU_SEARCH_BUTTON_SELECTOR: &str = "#su";
const ZHIHU_HOME_URL: &str = "https://www.zhihu.com";
const ZHIHU_SEARCH_URL: &str = "https://www.zhihu.com/search";
const ZHIHU_DOMAIN: &str = "www.zhihu.com";

#[derive(Debug, Clone, PartialEq)]
pub struct PlannedStep {
    pub action: Action,
    pub params: Value,
    pub expected_domain: String,
    pub log_message: String,
}

#[derive(Debug, Clone, PartialEq)]
pub struct TaskPlan {
    pub summary: String,
    pub steps: Vec<PlannedStep>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExecutionPreview {
    pub summary: String,
    pub steps: Vec<String>,
}

#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum PlannerError {
    #[error("unsupported instruction: {0}")]
    UnsupportedInstruction(String),
    #[error("missing search query in instruction")]
    MissingQuery,
}

pub fn plan_instruction(instruction: &str) -> Result<TaskPlan, PlannerError> {
    let trimmed = instruction.trim();
    if matches_exact(trimmed, &["打开百度"]) {
        return Ok(plan_homepage("已打开百度首页", BAIDU_URL, BAIDU_DOMAIN));
    }

    if let Some(query) = extract_query(trimmed, &["打开百度搜索", "打开百度并搜索"])? {
        return Ok(plan_baidu_search(query));
    }

    if matches_exact(trimmed, &["打开知乎"]) {
        return Ok(plan_homepage(
            "已打开知乎首页",
            ZHIHU_HOME_URL,
            ZHIHU_DOMAIN,
        ));
    }

    if let Some(query) = extract_query(trimmed, &["打开知乎搜索", "打开知乎并搜索"])? {
        return Ok(plan_zhihu_search(query));
    }

    Err(PlannerError::UnsupportedInstruction(trimmed.to_string()))
}

pub fn build_execution_preview(
    mode: PlannerMode,
    instruction: &str,
    page_url: Option<&str>,
    page_title: Option<&str>,
) -> Option<ExecutionPreview> {
    if matches!(mode, PlannerMode::LegacyDeterministic) {
        return None;
    }

    let trimmed = instruction.trim();
    if crate::runtime::is_zhihu_hotlist_task(trimmed, page_url, page_title) {
        return Some(build_zhihu_hotlist_preview(trimmed));
    }

    if let Ok(plan) = plan_instruction(trimmed) {
        return Some(ExecutionPreview {
            summary: format!("先规划再执行：{}", plan.summary),
            steps: plan
                .steps
                .into_iter()
                .map(|step| step.log_message)
                .collect(),
        });
    }

    Some(ExecutionPreview {
        summary: "先规划再执行当前任务".to_string(),
        steps: vec![
            "inspect current browser context".to_string(),
            "choose the required sgclaw runtime tools".to_string(),
            "execute and return the concrete result".to_string(),
        ],
    })
}

fn extract_query<'a>(
    instruction: &'a str,
    prefixes: &[&str],
) -> Result<Option<&'a str>, PlannerError> {
    let Some(query) = prefixes
        .iter()
        .find_map(|prefix| instruction.strip_prefix(prefix))
    else {
        return Ok(None);
    };

    let query = query.trim();
    if query.is_empty() {
        return Err(PlannerError::MissingQuery);
    }

    Ok(Some(query))
}

fn matches_exact(instruction: &str, candidates: &[&str]) -> bool {
    candidates.iter().any(|candidate| instruction == *candidate)
}

fn plan_homepage(summary: &str, url: &str, domain: &str) -> TaskPlan {
    TaskPlan {
        summary: summary.to_string(),
        steps: vec![PlannedStep {
            action: Action::Navigate,
            params: json!({ "url": url }),
            expected_domain: domain.to_string(),
            log_message: format!("navigate {url}"),
        }],
    }
}

fn plan_baidu_search(query: &str) -> TaskPlan {
    TaskPlan {
        summary: format!("已在百度搜索{query}"),
        steps: vec![
            PlannedStep {
                action: Action::Navigate,
                params: json!({ "url": BAIDU_URL }),
                expected_domain: BAIDU_DOMAIN.to_string(),
                log_message: "navigate https://www.baidu.com".to_string(),
            },
            PlannedStep {
                action: Action::Type,
                params: json!({
                    "selector": BAIDU_INPUT_SELECTOR,
                    "text": query,
                    "clear_first": true
                }),
                expected_domain: BAIDU_DOMAIN.to_string(),
                log_message: format!("type {query} into {BAIDU_INPUT_SELECTOR}"),
            },
            PlannedStep {
                action: Action::Click,
                params: json!({ "selector": BAIDU_SEARCH_BUTTON_SELECTOR }),
                expected_domain: BAIDU_DOMAIN.to_string(),
                log_message: format!("click {BAIDU_SEARCH_BUTTON_SELECTOR}"),
            },
        ],
    }
}

fn plan_zhihu_search(query: &str) -> TaskPlan {
    let url = Url::parse_with_params(ZHIHU_SEARCH_URL, &[("type", "content"), ("q", query)])
        .expect("valid Zhihu search URL");
    let url: String = url.into();

    TaskPlan {
        summary: format!("已在知乎搜索{query}"),
        steps: vec![PlannedStep {
            action: Action::Navigate,
            params: json!({ "url": url }),
            expected_domain: ZHIHU_DOMAIN.to_string(),
            log_message: format!("navigate {url}"),
        }],
    }
}

fn build_zhihu_hotlist_preview(instruction: &str) -> ExecutionPreview {
    let normalized = instruction.to_ascii_lowercase();
    if normalized.contains("dashboard") || instruction.contains("大屏") || instruction.contains("新标签页") {
        return ExecutionPreview {
            summary: "先规划再执行知乎热榜大屏生成".to_string(),
            steps: vec![
                "navigate https://www.zhihu.com/hot".to_string(),
                "getText main".to_string(),
                "call screen_html_export".to_string(),
                "return generated local .html path".to_string(),
            ],
        };
    }

    ExecutionPreview {
        summary: "先规划再执行知乎热榜 Excel 导出".to_string(),
        steps: vec![
            "navigate https://www.zhihu.com/hot".to_string(),
            "getText main".to_string(),
            "call openxml_office".to_string(),
            "return generated local .xlsx path".to_string(),
        ],
    }
}
