//! Multi-round prefetch protocol types.
//!
//! When the host does not support MCP `sampling/createMessage`, FURNACE cannot
//! call the LLM directly.  Instead it returns a `pending_prefetch` response
//! containing prompts that the host LLM must answer.  The host then calls
//! `execute_scroll` again with the completions.
//!
//! Three rounds:
//! 1. **Augmentation** — Gandalf verifies and suggests tasks.
//! 2. **Code generation** — Gimli produces code for each task.
//! 3. **Test & review** — Trinity generates tests, Legolas reviews code
//!    (bundled in one round, run in parallel by the host).

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

/// A prompt to be answered by the host LLM.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefetchPrompt {
    /// Unique identifier, e.g. `"gandalf-aug-SCR-123"` or `"gimli-gen-TASK-001"`.
    pub id: String,
    /// Agent that owns this prompt: `"Gandalf"`, `"Gimli"`, `"Trinity"`, `"Legolas"`.
    pub agent: String,
    /// Task this prompt is for (Some for Gimli/Trinity, None for Gandalf/Legolas).
    pub task_id: Option<String>,
    /// System prompt to use with the LLM.
    pub system_prompt: String,
    /// User prompt to use with the LLM.
    pub user_prompt: String,
    /// Human-readable description, e.g. `"Generate tests for src/auth.rs"`.
    pub description: String,
}

/// A completion returned by the host LLM in response to a `PrefetchPrompt`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefetchCompletion {
    /// Must match `PrefetchPrompt.id`.
    pub id: String,
    /// The host LLM's answer.
    pub response: String,
}

/// Build the standard `pending_prefetch` response JSON.
pub fn build_prefetch_response(
    scroll_id: &str,
    round: u8,
    prompts: Vec<PrefetchPrompt>,
    server_work: Vec<String>,
) -> Value {
    let next_step = format!(
        "Answer each prompt, then call execute_scroll with completions and prefetch_round: {}",
        round,
    );
    json!({
        "scroll_id": scroll_id,
        "status": "pending_prefetch",
        "round": round,
        "total_rounds": 3,
        "prompts": prompts,
        "server_work_completed": server_work,
        "next_step": next_step,
    })
}

// ===========================================================================
// Tests
// ===========================================================================

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn serde_round_trip_prompt() {
        let prompt = PrefetchPrompt {
            id: "gandalf-aug-SCR-123".into(),
            agent: "Gandalf".into(),
            task_id: None,
            system_prompt: "You are Gandalf.".into(),
            user_prompt: "Verify tasks.".into(),
            description: "Augment tasks for scroll SCR-123".into(),
        };
        let json = serde_json::to_string(&prompt).unwrap();
        let back: PrefetchPrompt = serde_json::from_str(&json).unwrap();
        assert_eq!(back.id, "gandalf-aug-SCR-123");
        assert_eq!(back.agent, "Gandalf");
        assert!(back.task_id.is_none());
        assert_eq!(back.system_prompt, "You are Gandalf.");
    }

    #[test]
    fn serde_round_trip_completion() {
        let completion = PrefetchCompletion {
            id: "gimli-gen-TASK-001".into(),
            response: "```rust\nfn main() {}\n```".into(),
        };
        let json = serde_json::to_string(&completion).unwrap();
        let back: PrefetchCompletion = serde_json::from_str(&json).unwrap();
        assert_eq!(back.id, "gimli-gen-TASK-001");
        assert!(back.response.contains("fn main()"));
    }

    #[test]
    fn serde_round_trip_prompt_with_task_id() {
        let prompt = PrefetchPrompt {
            id: "trinity-test-TASK-002".into(),
            agent: "Trinity".into(),
            task_id: Some("TASK-002".into()),
            system_prompt: "You are a test engineer.".into(),
            user_prompt: "Generate tests.".into(),
            description: "Generate tests for src/lib.rs".into(),
        };
        let json = serde_json::to_string(&prompt).unwrap();
        let back: PrefetchPrompt = serde_json::from_str(&json).unwrap();
        assert_eq!(back.task_id, Some("TASK-002".into()));
    }

    #[test]
    fn build_prefetch_response_structure() {
        let prompts = vec![PrefetchPrompt {
            id: "test-prompt-1".into(),
            agent: "Gimli".into(),
            task_id: Some("TASK-001".into()),
            system_prompt: "sys".into(),
            user_prompt: "usr".into(),
            description: "desc".into(),
        }];
        let response = build_prefetch_response(
            "SCR-123",
            2,
            prompts,
            vec!["Gandalf augmentation completed".into()],
        );

        assert_eq!(response["scroll_id"], "SCR-123");
        assert_eq!(response["status"], "pending_prefetch");
        assert_eq!(response["round"], 2);
        assert_eq!(response["total_rounds"], 3);
        assert_eq!(response["prompts"].as_array().unwrap().len(), 1);
        assert_eq!(response["server_work_completed"].as_array().unwrap().len(), 1);
        assert!(response["next_step"].as_str().unwrap().contains("prefetch_round: 2"));
    }
}
