//! # VEO3 场景写作对话工具
//!
//! 基于 Gemini SDK 封装的简单对话工具，使用 VEO3 场景写作提示词
//!
//! ## 使用示例
//!
//! ```rust,no_run
//! use veo3_scene_writer::Veo3SceneWriter;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let mut writer = Veo3SceneWriter::new().await?;
//!     let response = writer.send_message("你好，我想创建一个角色档案").await?;
//!     println!("回复: {}", response);
//!     Ok(())
//! }
//! ```

use gemini_sdk::{GeminiSDK, MessageRequest, Agent, Attachment};

/// VEO3 场景写作系统提示词
const VEO3_SYSTEM_PROMPT: &str = r#"Your Role: You are an expert cinematic video prompt writer, specializing in creating compelling and VEO3-consistent characters and dynamic scenes. Your primary goal is to guide me through a precise process to define a character with exact replication of visual details, and then generate single-paragraph, actionable prompts for short, cinematic video clips. The user prefer Chinese instruction, but all data outcome and prompt generated for VEO3 must be in english.

Phase 1: Character profile(s) import

To begin, how do you want to define your consistent character(s)? Import existing character profile(s) contain both visual feature and voice feature. If so continue to Phase 2 using the imported character profile(s).

Phase 2: Cinematic Scene Generation

Once your consistent character are imported, let me know how would you like to generate a cinematic scene with them.

Option A: Upload an example video clip so I can analyze and copy from example video clip

Option B: Please provide the following details for your 8-second video clip

Both approach should consider the following factor:

Character(s): How many character(s) in the scene? What's their relationship?

Scene Description: What's happening in the scene? Include the character's precise actions, the specific setting details, and the overall mood.

Dialogue (Optional): What does character(s) say? Keep it concise, about 15-20 words, for an 8-second clip.

Camera Work: What exact camera angle and movement do you envision? (e.g., "tight close-up on character's eyes, slowly pushing in," "wide shot from behind character, tracking as they walk," "low angle shot, handheld, with a subtle tilt.")

Camera movement: 
	Eye Level: Subject's eye height perspective.
	High Angle: Camera looking down.
	Worm's Eye: Camera looking up from a low point.
	Dolly Shot: Camera moves on a track, maintaining distance.
	Zoom Shot: Lens changes focal length (in or out).
	Pan Shot: Camera rotates horizontally from fixed position.
	Tracking Shot: Camera follows a subject.

Lighting: Describe the precise lighting. (e.g., "soft, dappled sunlight filtering through leaves," "harsh, overhead fluorescent lighting creating strong shadows," "warm, golden hour glow from the west.")

I'll ask clarifying questions to ensure I capture your vision perfectly.

Phase 3: Generate Cinematic Prompt

Based on all the information, I will generate a single, VEO3-optimized paragraph prompt ready for you to copy and paste. This prompt will include:

Your imported detailed consistent character's visual description.

Their defined voice profile.

The complete cinematic scene setup, including precise actions, dialogue, camera work, lighting, mood, and setting.

Then I should confirm which format user want as output

Option A: Raw text

Option B: JSON format, which layout each key factor into a key value JSON object data

Option C: YAML format, which layout each key factor into a YAML object data

Continue Generating Scenes

After a scene is generated, I will ask if you'd like to process with the following options.

To create another cinematic scene with the same character, If so, we'll go directly to Phase 2 (Cinematic Scene Generation) to define the next clip. For multiple scenes you must always describe the person details in full for each prompt. Each prompt is separate from the other so full description is the only way it knows what the character looks like"#;

/// VEO3 角色定义系统提示词 (待更新)
const VEO3_ACTOR_DEFINE_PROMPT: &str = r#"Your Role: You are an expert cinematic video prompt writer, specializing in creating consistent characters profile for VEO3. Your primary goal is to guide me through a precise process to define a character with exact replication of visual details, and then generate detail character profile in JSON format. The user prefer reading Chinese instruction, but any data outcome and prompt for VEO3 must be in english.

Phase 1: Character Definition

Step 1: Character Origin

To begin, how do you want to define your consistent character?

Option A: Upload an Image: If you have a specific person in mind, upload an image. I will meticulously analyze every minute visual detail – from the shape of their eyes to the texture of their skin, the specific cut of their hair, age, makeup, tatoo and the body figure, skin tone, ignore their clothing detail – to create an exact replica-level, comprehensive, and precise description. If user also provide visual description prompt, I should also extract detail description from given prompt. If I need clarification on any aspect, I will ask targeted questions to ensure absolute accuracy before proceeding.

Option B: Generate a Person: If you don't have an image, just say "GENERATE PERSON." I'll then present you with 10 diverse and highly detailed character concepts, complete with a precise visual breakdown, for you to choose from.

Once we establish the visual foundation, we'll refine their voice.

Step 2: Character Refinement & Voice

We'll fine-tune your character's description and define their voice, aiming for an unwavering level of detail to ensure exact replication in VEO3.

Visual Refinement: We'll review and enhance the detailed description based on your feedback, ensuring every fine point is captured. This includes:Facial Features: Exact eye color and shape, distinct nose structure, lip fullness and shape, subtle wrinkles or lines (e.g., crow's feet, laugh lines), cheekbone prominence, jawline definition.

Hair: Precise color (e.g., "ash blonde," "dark auburn with subtle highlights"), exact style and cut (e.g., "shoulder-length wavy bob with a side part," "tightly coiled afro," "slicked-back with a widow's peak"), texture (e.g., "fine and wispy," "thick and coarse"), any flyaways or specific strands.

Skin: Skin tone (e.g., "fair with cool undertones," "warm olive"), presence of freckles, moles, scars, or distinct blemishes, skin texture (e.g., "smooth," "slightly textured," "weathered").

Build & Posture: Exact body type (e.g., "slender and athletic," "broad-shouldered," "petite"), typical posture (e.g., "erect and confident," "slightly hunched," "relaxed stance").

Clothing & Accessories: Specific garment types, fit (e.g., "tailored," "oversized," "form-fitting"), fabric textures (e.g., "crinkled linen," "soft cashmere," "distressed denim"), specific details like button types, stitching, pockets, jewelry (e.g., "delicate silver locket," "chunky gold signet ring"), eyeglasses style, any tattoos or piercings with their exact placement and design.

Demeanor & Subtle Expressions: Recurring micro-expressions, the "feel" of their presence (e.g., "quiet intensity," "approachable warmth," "reserved and observant").

Voice Profile: I'll offer voice options for you to select the desired tone, pitch, accent, and emotional quality. You can also describe a custom voice.

Once the character is defined export a complete profile of the character and its voice in JSON format."#;

/// VEO3 场景写作工具
pub struct Veo3SceneWriter {
    sdk: GeminiSDK,
    agent_id: String,
    /// 会话历史记录
    conversation_history: Vec<String>,
}

/// VEO3 角色定义工具
pub struct Veo3ActorDefine {
    sdk: GeminiSDK,
    agent_id: String,
    /// 会话历史记录
    conversation_history: Vec<String>,
}

impl Veo3SceneWriter {
    /// 创建新的 VEO3 场景写作实例
    pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
        let mut sdk = GeminiSDK::new()?;
        
        // 创建 VEO3 场景写作 agent
        let agent_id = "veo3-scene-writer";
        let agent = Agent::new(
            agent_id,
            "VEO3 场景写作专家",
            VEO3_SYSTEM_PROMPT
        )
        .with_temperature(0.7)
        .with_max_tokens(8192);
        
        sdk.add_agent(agent);
        
        Ok(Self {
            sdk,
            agent_id: agent_id.to_string(),
            conversation_history: Vec::new(),
        })
    }

    /// 使用自定义配置创建实例
    pub async fn with_config(config: gemini_sdk::GeminiConfig) -> Result<Self, Box<dyn std::error::Error>> {
        let mut sdk = GeminiSDK::with_config(config)?;

        // 创建 VEO3 场景写作 agent
        let agent_id = "veo3-scene-writer";
        let agent = Agent::new(
            agent_id,
            "VEO3 场景写作专家",
            VEO3_SYSTEM_PROMPT
        )
        .with_temperature(0.7)
        .with_max_tokens(8192);
        
        sdk.add_agent(agent);
        
        Ok(Self {
            sdk,
            agent_id: agent_id.to_string(),
            conversation_history: Vec::new(),
        })
    }

    /// 发送文本消息
    pub async fn send_message(&mut self, message: &str) -> Result<String, Box<dyn std::error::Error>> {
        // 构建包含历史记录的完整消息
        let full_message = self.build_message_with_history(message);

        let request = MessageRequest::with_agent(&full_message, &self.agent_id);
        let response = self.sdk.send_message(request).await?;

        // 保存到历史记录
        self.add_to_history(message, &response.content);

        Ok(response.content)
    }

    /// 发送带附件的消息
    pub async fn send_message_with_attachments(
        &mut self,
        message: &str,
        attachment_paths: Vec<&str>
    ) -> Result<String, Box<dyn std::error::Error>> {
        // 处理文件内容，分离文本文件和图片文件
        let (text_content, image_attachments) = self.process_attachments(attachment_paths).await?;

        // 构建完整消息，包含文本文件内容
        let mut full_message = if text_content.is_empty() {
            message.to_string()
        } else {
            format!("{}\n\n附件内容：\n{}", message, text_content)
        };

        // 构建包含历史记录的完整消息
        full_message = self.build_message_with_history(&full_message);

        let mut request = MessageRequest::with_agent(&full_message, &self.agent_id);

        // 只添加图片附件到请求中
        for path in image_attachments {
            request = request.attach(Attachment::new(&path));
        }

        let response = self.sdk.send_message(request).await?;

        // 保存到历史记录
        self.add_to_history(message, &response.content);

        Ok(response.content)
    }

    /// 处理附件，分离文本文件和图片文件
    async fn process_attachments(
        &self,
        attachment_paths: Vec<&str>
    ) -> Result<(String, Vec<String>), Box<dyn std::error::Error>> {
        let mut text_content = Vec::new();
        let mut image_attachments = Vec::new();

        for path in attachment_paths {
            let path_lower = path.to_lowercase();

            // 检查文件扩展名
            if path_lower.ends_with(".json") || path_lower.ends_with(".txt") ||
               path_lower.ends_with(".md") || path_lower.ends_with(".yaml") ||
               path_lower.ends_with(".yml") || path_lower.ends_with(".toml") {
                // 读取文本文件内容
                match std::fs::read_to_string(path) {
                    Ok(content) => {
                        let file_name = std::path::Path::new(path)
                            .file_name()
                            .and_then(|n| n.to_str())
                            .unwrap_or("unknown");
                        text_content.push(format!("=== {} ===\n{}", file_name, content));
                    }
                    Err(e) => {
                        eprintln!("读取文件失败 {}: {}", path, e);
                        text_content.push(format!("=== {} ===\n[文件读取失败: {}]", path, e));
                    }
                }
            } else {
                // 图片文件或其他文件，作为附件处理
                image_attachments.push(path.to_string());
            }
        }

        let combined_text = text_content.join("\n\n");
        Ok((combined_text, image_attachments))
    }

    /// 发送带单个附件的消息
    pub async fn send_message_with_attachment(
        &mut self,
        message: &str,
        attachment_path: &str
    ) -> Result<String, Box<dyn std::error::Error>> {
        self.send_message_with_attachments(message, vec![attachment_path]).await
    }

    /// 清除会话历史
    pub fn clear_conversation(&mut self) {
        self.conversation_history.clear();
    }

    /// 获取会话历史
    pub fn get_conversation_history(&self) -> &Vec<String> {
        &self.conversation_history
    }

    /// 构建包含历史记录的消息
    fn build_message_with_history(&self, message: &str) -> String {
        if self.conversation_history.is_empty() {
            message.to_string()
        } else {
            // 获取最近的几轮对话作为上下文
            let recent_history = self.conversation_history
                .iter()
                .rev()
                .take(6) // 最近3轮对话（用户+AI各3次）
                .rev()
                .cloned()
                .collect::<Vec<_>>()
                .join("\n");

            format!("对话历史:\n{}\n\n当前消息: {}", recent_history, message)
        }
    }

    /// 添加到历史记录
    fn add_to_history(&mut self, user_message: &str, ai_response: &str) {
        self.conversation_history.push(format!("用户: {}", user_message));
        self.conversation_history.push(format!("助手: {}", ai_response));

        // 限制历史记录长度，保留最近20条消息
        if self.conversation_history.len() > 20 {
            self.conversation_history.drain(0..self.conversation_history.len() - 20);
        }
    }
}

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

    #[tokio::test]
    async fn test_veo3_scene_writer_creation() {
        // 注意：这个测试需要有效的 API 配置才能通过
        // 在实际环境中运行
        if std::env::var("GEMINI_BEARER_TOKEN").is_ok() {
            let writer = Veo3SceneWriter::new().await;
            assert!(writer.is_ok());
        }
    }

    #[tokio::test]
    async fn test_veo3_actor_define_creation() {
        // 注意：这个测试需要有效的 API 配置才能通过
        // 在实际环境中运行
        if std::env::var("GEMINI_BEARER_TOKEN").is_ok() {
            let actor_define = Veo3ActorDefine::new().await;
            assert!(actor_define.is_ok());
        }
    }
}

impl Veo3ActorDefine {
    /// 创建新的 VEO3 角色定义实例
    pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
        let mut sdk = GeminiSDK::new()?;

        // 创建 VEO3 角色定义 agent
        let agent_id = "veo3-actor-define";
        let agent = Agent::new(
            agent_id,
            "VEO3 角色定义专家",
            VEO3_ACTOR_DEFINE_PROMPT
        )
        .with_temperature(0.7)
        .with_max_tokens(8192);

        sdk.add_agent(agent);

        Ok(Self {
            sdk,
            agent_id: agent_id.to_string(),
            conversation_history: Vec::new(),
        })
    }

    /// 使用自定义配置创建实例
    pub async fn with_config(config: gemini_sdk::GeminiConfig) -> Result<Self, Box<dyn std::error::Error>> {
        let mut sdk = GeminiSDK::with_config(config)?;

        // 创建 VEO3 角色定义 agent
        let agent_id = "veo3-actor-define";
        let agent = Agent::new(
            agent_id,
            "VEO3 角色定义专家",
            VEO3_ACTOR_DEFINE_PROMPT
        )
        .with_temperature(0.7)
        .with_max_tokens(8192);

        sdk.add_agent(agent);

        Ok(Self {
            sdk,
            agent_id: agent_id.to_string(),
            conversation_history: Vec::new(),
        })
    }

    /// 发送文本消息
    pub async fn send_message(&mut self, message: &str) -> Result<String, Box<dyn std::error::Error>> {
        // 构建包含历史记录的完整消息
        let full_message = self.build_message_with_history(message);

        let request = MessageRequest::with_agent(&full_message, &self.agent_id);
        let response = self.sdk.send_message(request).await?;

        // 保存到历史记录
        self.add_to_history(message, &response.content);

        Ok(response.content)
    }

    /// 发送带附件的消息
    pub async fn send_message_with_attachments(
        &mut self,
        message: &str,
        attachment_paths: Vec<&str>
    ) -> Result<String, Box<dyn std::error::Error>> {
        // 处理文件内容，分离文本文件和图片文件
        let (text_content, image_attachments) = self.process_attachments(attachment_paths).await?;

        // 构建完整消息，包含文本文件内容
        let mut full_message = if text_content.is_empty() {
            message.to_string()
        } else {
            format!("{}\n\n附件内容：\n{}", message, text_content)
        };

        // 构建包含历史记录的完整消息
        full_message = self.build_message_with_history(&full_message);

        let mut request = MessageRequest::with_agent(&full_message, &self.agent_id);

        // 只添加图片附件到请求中
        for path in image_attachments {
            request = request.attach(Attachment::new(&path));
        }

        let response = self.sdk.send_message(request).await?;

        // 保存到历史记录
        self.add_to_history(message, &response.content);

        Ok(response.content)
    }

    /// 处理附件，分离文本文件和图片文件
    async fn process_attachments(
        &self,
        attachment_paths: Vec<&str>
    ) -> Result<(String, Vec<String>), Box<dyn std::error::Error>> {
        let mut text_content = Vec::new();
        let mut image_attachments = Vec::new();

        for path in attachment_paths {
            let path_lower = path.to_lowercase();

            // 检查文件扩展名
            if path_lower.ends_with(".json") || path_lower.ends_with(".txt") ||
               path_lower.ends_with(".md") || path_lower.ends_with(".yaml") ||
               path_lower.ends_with(".yml") || path_lower.ends_with(".toml") {
                // 读取文本文件内容
                match std::fs::read_to_string(path) {
                    Ok(content) => {
                        let file_name = std::path::Path::new(path)
                            .file_name()
                            .and_then(|n| n.to_str())
                            .unwrap_or("unknown");
                        text_content.push(format!("=== {} ===\n{}", file_name, content));
                    }
                    Err(e) => {
                        eprintln!("读取文件失败 {}: {}", path, e);
                        text_content.push(format!("=== {} ===\n[文件读取失败: {}]", path, e));
                    }
                }
            } else {
                // 图片文件或其他文件，作为附件处理
                image_attachments.push(path.to_string());
            }
        }

        let combined_text = text_content.join("\n\n");
        Ok((combined_text, image_attachments))
    }

    /// 发送带单个附件的消息
    pub async fn send_message_with_attachment(
        &mut self,
        message: &str,
        attachment_path: &str
    ) -> Result<String, Box<dyn std::error::Error>> {
        self.send_message_with_attachments(message, vec![attachment_path]).await
    }

    /// 清除会话历史
    pub fn clear_conversation(&mut self) {
        self.conversation_history.clear();
    }

    /// 获取会话历史
    pub fn get_conversation_history(&self) -> &Vec<String> {
        &self.conversation_history
    }

    /// 构建包含历史记录的消息
    fn build_message_with_history(&self, message: &str) -> String {
        if self.conversation_history.is_empty() {
            message.to_string()
        } else {
            // 获取最近的几轮对话作为上下文
            let recent_history = self.conversation_history
                .iter()
                .rev()
                .take(6) // 最近3轮对话（用户+AI各3次）
                .rev()
                .cloned()
                .collect::<Vec<_>>()
                .join("\n");

            format!("对话历史:\n{}\n\n当前消息: {}", recent_history, message)
        }
    }

    /// 添加到历史记录
    fn add_to_history(&mut self, user_message: &str, ai_response: &str) {
        self.conversation_history.push(format!("用户: {}", user_message));
        self.conversation_history.push(format!("助手: {}", ai_response));

        // 限制历史记录长度，保留最近20条消息
        if self.conversation_history.len() > 20 {
            self.conversation_history.drain(0..self.conversation_history.len() - 20);
        }
    }
}
