//! Deep-search playbook and trace-artifact contracts used by advanced trace-oriented MCP tools.

use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::mcp::server::FriggMcpServer;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum DeepSearchStepTool {
    Workspace,
    ReadFile,
    SearchText,
    SearchSymbol,
    FindReferences,
}

impl DeepSearchStepTool {
    const ALL: [Self; 5] = [
        Self::Workspace,
        Self::ReadFile,
        Self::SearchText,
        Self::SearchSymbol,
        Self::FindReferences,
    ];

    fn from_tool_name(tool_name: &str) -> Option<Self> {
        match tool_name {
            "workspace" => Some(Self::Workspace),
            "read_file" => Some(Self::ReadFile),
            "search_text" => Some(Self::SearchText),
            "search_symbol" => Some(Self::SearchSymbol),
            "find_references" => Some(Self::FindReferences),
            _ => None,
        }
    }

    pub(crate) const fn as_str(self) -> &'static str {
        match self {
            Self::Workspace => "workspace",
            Self::ReadFile => "read_file",
            Self::SearchText => "search_text",
            Self::SearchSymbol => "search_symbol",
            Self::FindReferences => "find_references",
        }
    }
}

pub(crate) fn allowed_step_tools() -> &'static [&'static str] {
    const ALLOWED_STEP_TOOLS: [&str; 5] = [
        DeepSearchStepTool::ALL[0].as_str(),
        DeepSearchStepTool::ALL[1].as_str(),
        DeepSearchStepTool::ALL[2].as_str(),
        DeepSearchStepTool::ALL[3].as_str(),
        DeepSearchStepTool::ALL[4].as_str(),
    ];
    &ALLOWED_STEP_TOOLS
}

/// Ordered sequence of MCP tool calls agents can run and replay as a trace workflow.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchPlaybook {
    pub playbook_id: String,
    pub steps: Vec<DeepSearchPlaybookStep>,
}

/// One playbook step referencing a whitelisted MCP tool name and JSON params.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchPlaybookStep {
    pub step_id: String,
    pub tool_name: String,
    #[serde(default)]
    pub params: Value,
}

/// Serialized trace of playbook execution suitable for replay and citation composition.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchTraceArtifact {
    pub trace_schema: String,
    pub playbook_id: String,
    pub step_count: usize,
    pub steps: Vec<DeepSearchTraceStep>,
}

/// Per-step trace record capturing params and the normalized tool outcome.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchTraceStep {
    pub step_index: usize,
    pub step_id: String,
    pub tool_name: String,
    pub params_json: String,
    pub outcome: DeepSearchTraceOutcome,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
/// Normalized success or transport error outcome for one traced MCP tool call.
#[serde(tag = "status", rename_all = "snake_case")]
pub enum DeepSearchTraceOutcome {
    Ok {
        response_json: String,
    },
    Err {
        code: String,
        message: String,
        error_code: Option<String>,
    },
}

/// Result of replaying a playbook against an expected trace artifact.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchReplayCheck {
    pub matches: bool,
    pub diff: Option<String>,
    pub replayed: DeepSearchTraceArtifact,
}

/// Answer text with claim and file-span citations derived from a trace artifact.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchCitationPayload {
    pub answer_schema: String,
    pub playbook_id: String,
    pub answer: String,
    pub claims: Vec<DeepSearchClaim>,
    pub citations: Vec<DeepSearchCitation>,
}

/// One answer claim linked to citation ids produced from a deep-search trace artifact.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchClaim {
    pub claim_id: String,
    pub text: String,
    pub citation_ids: Vec<String>,
}

/// Repository file span citation anchored to one traced MCP tool call.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchCitation {
    pub citation_id: String,
    pub tool_call_id: String,
    pub tool_name: String,
    pub repository_id: String,
    pub path: String,
    pub span: DeepSearchFileSpan,
}

/// Inclusive line/column span within one cited repository file.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeepSearchFileSpan {
    pub start_line: usize,
    pub start_column: usize,
    pub end_line: usize,
    pub end_column: usize,
}

/// Runs deep-search playbooks against a dedicated MCP server instance.
#[derive(Clone)]
pub struct DeepSearchHarness {
    server: FriggMcpServer,
}

#[path = "deep_search/runtime.rs"]
mod runtime;
#[cfg(test)]
#[path = "deep_search/tests.rs"]
mod tests;
