use crate::command::chat::app::{AskOption, AskQuestion, AskRequest};
use crate::command::chat::tools::{Tool, ToolResult, schema_to_tool_params};
use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::Value;
use std::sync::{Arc, Mutex, atomic::AtomicBool, mpsc};

// ========== Plan Mode State ==========

/// Plan mode 内部状态（受 Mutex 保护，保证原子性）
struct PlanModeInner {
    active: bool,
    plan_file_path: Option<String>,
}

/// Plan Mode 全局状态（跨工具共享）
///
/// 使用单一 Mutex 保护 active + plan_file_path，避免以下并发问题：
/// - enter() 的 TOCTOU 竞态（先检查 is_active 再进入）
/// - exit() 不清理 plan_file_path
/// - is_active() 与 get_plan_file_path() 之间状态不一致
pub struct PlanModeState {
    inner: Mutex<PlanModeInner>,
}

impl Default for PlanModeState {
    fn default() -> Self {
        Self::new()
    }
}

impl PlanModeState {
    pub fn new() -> Self {
        Self {
            inner: Mutex::new(PlanModeInner {
                active: false,
                plan_file_path: None,
            }),
        }
    }

    /// 检查是否处于 plan mode
    pub fn is_active(&self) -> bool {
        self.inner.lock().map(|g| g.active).unwrap_or(false)
    }

    /// 进入 plan mode，同时设置 plan 文件路径
    /// 返回 Ok(()) 表示成功进入，Err(msg) 表示已在 plan mode
    pub fn enter(&self, path: String) -> Result<(), String> {
        match self.inner.lock() {
            Ok(mut guard) => {
                if guard.active {
                    return Err("Already in plan mode. Use ExitPlanMode to exit.".to_string());
                }
                guard.active = true;
                guard.plan_file_path = Some(path);
                Ok(())
            }
            Err(e) => Err(format!("Lock poisoned: {}", e)),
        }
    }

    /// 退出 plan mode，同时清理 plan_file_path 和 plan 文件
    pub fn exit(&self) {
        if let Ok(mut guard) = self.inner.lock() {
            // 清理 plan 文件
            if let Some(ref path) = guard.plan_file_path {
                let _ = std::fs::remove_file(path);
            }
            guard.active = false;
            guard.plan_file_path = None;
        }
    }

    /// 原子地检查是否 active 并获取 plan 文件路径
    /// 返回 (is_active, plan_file_path)
    pub fn get_state(&self) -> (bool, Option<String>) {
        match self.inner.lock() {
            Ok(guard) => (guard.active, guard.plan_file_path.clone()),
            Err(_) => (false, None),
        }
    }

    /// 获取 plan 文件路径（仅在 active 时有意义）
    pub fn get_plan_file_path(&self) -> Option<String> {
        self.inner.lock().ok()?.plan_file_path.clone()
    }
}

/// plan mode 下允许执行的工具白名单
pub const PLAN_MODE_WHITELIST: &[&str] = &[
    "Read",
    "Glob",
    "Grep",
    "WebFetch",
    "WebSearch",
    "Ask",
    "Compact",
    "TodoRead",
    "TodoWrite",
    "TaskOutput",
    "Task",
    "EnterPlanMode",
    "ExitPlanMode",
    "EnterWorktree",
    "ExitWorktree",
];

/// 检查工具是否在 plan mode 白名单中
pub fn is_allowed_in_plan_mode(tool_name: &str) -> bool {
    PLAN_MODE_WHITELIST.contains(&tool_name)
}

// ========== EnterPlanModeTool ==========

/// EnterPlanMode 参数
#[derive(Deserialize, JsonSchema)]
struct EnterPlanModeParams {
    /// Optional short description of what you plan to investigate
    #[serde(default)]
    description: Option<String>,
}

pub struct EnterPlanModeTool {
    pub plan_state: Arc<PlanModeState>,
}

impl EnterPlanModeTool {
    pub const NAME: &'static str = "EnterPlanMode";
}

impl Tool for EnterPlanModeTool {
    fn name(&self) -> &str {
        Self::NAME
    }

    fn description(&self) -> &str {
        r#"
        Enter plan mode to explore the codebase and design an implementation approach before writing code.
        In plan mode, only read-only tools (Read, Glob, Grep, WebFetch, WebSearch, Ask, etc.) are available.
        Write tools (Bash, Write, Edit, etc.) will be blocked until plan mode is exited.

        Use this proactively before starting non-trivial implementation tasks. Prefer using EnterPlanMode when ANY of these apply:
        - New feature implementation with architectural decisions
        - Multiple valid approaches exist and user should choose
        - Code modifications that affect existing behavior
        - Multi-file changes (touching more than 2-3 files)
        - Unclear requirements that need exploration first

        Do NOT use for: single-line fixes, typos, or purely research/exploration tasks.
        "#
    }

    fn parameters_schema(&self) -> Value {
        schema_to_tool_params::<EnterPlanModeParams>()
    }

    fn execute(&self, arguments: &str, _cancelled: &Arc<AtomicBool>) -> ToolResult {
        let params: EnterPlanModeParams =
            serde_json::from_str(arguments).unwrap_or(EnterPlanModeParams { description: None });
        let description = params
            .description
            .as_deref()
            .unwrap_or("implementation plan");

        // 创建 plan 文件（用 PID 隔离，避免多实例共享同一目录时互相覆盖）
        let plan_dir = crate::command::chat::permission::JcliConfig::ensure_config_dir()
            .unwrap_or_else(|| std::env::current_dir().unwrap_or_default().join(".jcli"));
        let _ = std::fs::create_dir_all(&plan_dir);
        let plan_file = plan_dir.join(format!("plan-{}.md", std::process::id()));
        let plan_path = plan_file.display().to_string();

        // 写入初始模板
        let template = format!("# Plan: {}\n\n## Steps\n\n1. \n\n## Notes\n\n", description);
        let _ = std::fs::write(&plan_file, &template);

        // 原子性地进入 plan mode（内部检查 is_active，避免 TOCTOU 竞态）
        match self.plan_state.enter(plan_path.clone()) {
            Ok(()) => ToolResult {
                output: format!(
                    "Entered plan mode. Plan file created at: {}\n\
                     In plan mode, only read-only tools are available.\n\
                     Write your plan to the plan file, then use ExitPlanMode when ready for user approval.",
                    plan_path
                ),
                is_error: false,
                images: vec![],
            },
            Err(msg) => ToolResult {
                output: msg,
                is_error: false,
                images: vec![],
            },
        }
    }

    fn requires_confirmation(&self) -> bool {
        false
    }
}

// ========== ExitPlanModeTool ==========

/// ExitPlanMode 参数
#[derive(Deserialize, JsonSchema)]
#[allow(dead_code)]
struct ExitPlanModeParams {
    /// Optional list of prompt-based permissions needed to implement the plan
    #[serde(default)]
    #[serde(rename = "allowedPrompts")]
    allowed_prompts: Option<Vec<AllowedPrompt>>,
}

/// 计划实施所需的权限描述
#[derive(Deserialize, JsonSchema)]
#[allow(dead_code)]
struct AllowedPrompt {
    /// The tool this prompt applies to (e.g. 'Bash')
    #[serde(default)]
    tool: Option<String>,
    /// Semantic description of the action (e.g. 'run tests')
    #[serde(default)]
    prompt: Option<String>,
}

pub struct ExitPlanModeTool {
    pub plan_state: Arc<PlanModeState>,
    pub ask_tx: mpsc::Sender<AskRequest>,
}

impl ExitPlanModeTool {
    pub const NAME: &'static str = "ExitPlanMode";
}

impl Tool for ExitPlanModeTool {
    fn name(&self) -> &str {
        Self::NAME
    }

    fn description(&self) -> &str {
        r#"
        Exit plan mode and submit the plan for user approval.
        Reads the plan file and presents it to the user for review.
        If approved, plan mode is deactivated and write tools become available again.
        If rejected, plan mode remains active so you can revise the plan.
        "#
    }

    fn parameters_schema(&self) -> Value {
        schema_to_tool_params::<ExitPlanModeParams>()
    }

    fn execute(&self, _arguments: &str, _cancelled: &Arc<AtomicBool>) -> ToolResult {
        if !self.plan_state.is_active() {
            return ToolResult {
                output: "Not in plan mode. Use EnterPlanMode first.".to_string(),
                is_error: true,
                images: vec![],
            };
        }

        // 读取 plan 文件内容
        let plan_content = match self.plan_state.get_plan_file_path() {
            Some(path) => match std::fs::read_to_string(&path) {
                Ok(content) => content,
                Err(e) => {
                    return ToolResult {
                        output: format!("Failed to read plan file: {}", e),
                        is_error: true,
                        images: vec![],
                    };
                }
            },
            None => {
                return ToolResult {
                    output: "No plan file path set.".to_string(),
                    is_error: true,
                    images: vec![],
                };
            }
        };

        // 通过 Ask 机制发送审批请求
        let (response_tx, response_rx) = mpsc::channel::<String>();

        let question_text = format!(
            "Please review the implementation plan:\n\n{}\n\nDo you approve this plan?",
            plan_content
        );

        let ask_request = AskRequest {
            questions: vec![AskQuestion {
                question: question_text,
                header: "Plan Review".to_string(),
                options: vec![
                    AskOption {
                        label: "Approve".to_string(),
                        description: "Approve the plan and proceed with implementation".to_string(),
                    },
                    AskOption {
                        label: "Reject".to_string(),
                        description: "Reject the plan and stay in plan mode to revise".to_string(),
                    },
                ],
                multi_select: false,
            }],
            response_tx,
        };

        if self.ask_tx.send(ask_request).is_err() {
            return ToolResult {
                output: "Failed to send approval request (main thread may have exited)".to_string(),
                is_error: true,
                images: vec![],
            };
        }

        // 阻塞等待用户审批结果
        match response_rx.recv() {
            Ok(response) => {
                // 解析用户选择
                let approved = response.contains("Approve");
                if approved {
                    self.plan_state.exit();
                    ToolResult {
                        output: "Plan approved! Exited plan mode. You can now proceed with implementation.".to_string(),
                        is_error: false,
                        images: vec![],
                    }
                } else {
                    // 保持 plan mode，让 agent 修改 plan
                    ToolResult {
                        output: format!(
                            "Plan was not approved. Still in plan mode. User response: {}\nPlease revise your plan and try ExitPlanMode again.",
                            response
                        ),
                        is_error: false,
                        images: vec![],
                    }
                }
            }
            Err(_) => ToolResult {
                output: "Connection lost while waiting for approval".to_string(),
                is_error: true,
                images: vec![],
            },
        }
    }

    fn requires_confirmation(&self) -> bool {
        false
    }
}
