//! 数学公式渲染模块 - Phase 3
//! 
//! 支持 LaTeX 数学公式渲染 (KaTeX)

use anyhow::Result;
use pulldown_cmark::{Parser, Options, html};
use regex::Regex;
use serde::{Deserialize, Serialize};

/// 公式类型
#[derive(Debug, Clone, PartialEq)]
pub enum MathType {
    /// 行内公式 $...$
    Inline,
    /// 块级公式 $$...$$
    Display,
}

/// 数学公式
#[derive(Debug, Clone)]
pub struct MathFormula {
    /// 公式类型
    pub math_type: MathType,
    /// LaTeX 源码
    pub latex: String,
    /// 渲染后的 HTML
    pub rendered_html: Option<String>,
}

/// KaTeX 配置
#[derive(Debug, Clone, Serialize)]
pub struct KatexConfig {
    /// 是否启用
    pub enabled: bool,
    /// KaTeX CSS CDN URL
    pub css_url: String,
    /// KaTeX JS CDN URL
    pub js_url: String,
    /// 是否自动渲染
    pub auto_render: bool,
}

impl Default for KatexConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            css_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css".to_string(),
            js_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js".to_string(),
            auto_render: true,
        }
    }
}

/// 数学公式渲染器
pub struct MathRenderer {
    config: KatexConfig,
    inline_regex: Regex,
    display_regex: Regex,
}

impl MathRenderer {
    /// 创建数学公式渲染器
    pub fn new(config: KatexConfig) -> Result<Self> {
        // 正则表达式匹配行内公式 $...$
        let inline_regex = Regex::new(r"\$([^$]+)\$")?;
        // 正则表达式匹配块级公式 $$...$$
        let display_regex = Regex::new(r"\$\$([^\$]+)\$\$")?;
        
        Ok(Self {
            config,
            inline_regex,
            display_regex,
        })
    }
    
    /// 从 Markdown 提取公式
    pub fn extract_formulas(&self, markdown: &str) -> Vec<MathFormula> {
        let mut formulas = Vec::new();
        
        // 提取块级公式
        for cap in self.display_regex.captures_iter(markdown) {
            if let Some(latex) = cap.get(1) {
                formulas.push(MathFormula {
                    math_type: MathType::Display,
                    latex: latex.as_str().to_string(),
                    rendered_html: None,
                });
            }
        }
        
        // 提取行内公式
        for cap in self.inline_regex.captures_iter(markdown) {
            if let Some(latex) = cap.get(1) {
                formulas.push(MathFormula {
                    math_type: MathType::Inline,
                    latex: latex.as_str().to_string(),
                    rendered_html: None,
                });
            }
        }
        
        formulas
    }
    
    /// 渲染 Markdown 中的公式为 HTML
    pub fn render_markdown(&self, markdown: &str) -> String {
        if !self.config.enabled {
            return markdown.to_string();
        }
        
        // 先渲染块级公式
        let mut result = self.display_regex.replace_all(markdown, |caps: &regex::Captures| {
            let latex = caps.get(1).map(|m| m.as_str()).unwrap_or("");
            self.render_latex(latex, MathType::Display)
        }).to_string();
        
        // 再渲染行内公式
        result = self.inline_regex.replace_all(&result, |caps: &regex::Captures| {
            let latex = caps.get(1).map(|m| m.as_str()).unwrap_or("");
            self.render_latex(latex, MathType::Inline)
        }).to_string();
        
        result
    }
    
    /// 渲染单个 LaTeX 公式
    pub fn render_latex(&self, latex: &str, math_type: MathType) -> String {
        match math_type {
            MathType::Display => {
                // 块级公式使用 display 模式
                format!(
                    r#"<span class="katex-display"><span class="katex"><span class="katex-html"><span class="base">{}</span></span></span></span>"#,
                    latex
                )
            }
            MathType::Inline => {
                // 行内公式
                format!(
                    r#"<span class="katex"><span class="katex-html"><span class="base">{}</span></span></span>"#,
                    latex
                )
            }
        }
    }
    
    /// 生成完整的 HTML 文档（包含 KaTeX 资源）
    pub fn generate_html(&self, content: &str, title: &str) -> String {
        let rendered_content = self.render_markdown(content);
        
        // 使用 pulldown-cmark 渲染 Markdown
        let mut options = Options::empty();
        options.insert(Options::ENABLE_STRIKETHROUGH);
        options.insert(Options::ENABLE_TABLES);
        options.insert(Options::ENABLE_TASKLISTS);
        
        let parser = Parser::new_ext(&rendered_content, options);
        let mut html_body = String::new();
        html::push_html(&mut html_body, parser);
        
        // 生成完整 HTML
        format!(
            r#"<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{}</title>
    <link rel="stylesheet" href="{}">
    <script defer src="{}"></script>
    <style>
        :root {{
            --bg-primary: #1a1a2e;
            --bg-secondary: #16213e;
            --text-primary: #eaeaea;
            --accent-color: #00adb5;
        }}
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
            font-size: 16px;
            line-height: 1.6;
            background-color: var(--bg-primary);
            color: var(--text-primary);
            padding: 20px;
            max-width: 900px;
            margin: 0 auto;
        }}
        .katex {{
            font-size: 1.1em;
        }}
        .katex-display {{
            overflow-x: auto;
            overflow-y: hidden;
            padding: 10px 0;
        }}
        .math-block {{
            background: rgba(0, 173, 181, 0.1);
            padding: 15px;
            border-radius: 6px;
            margin: 20px 0;
            text-align: center;
        }}
    </style>
</head>
<body>
    {}
    <script>
        // 自动渲染 KaTeX 公式
        if (typeof renderMathInElement === 'function') {{
            renderMathInElement(document.body, {{
                delimiters: [
                    {{left: '$$', right: '$$', display: true}},
                    {{left: '$', right: '$', display: false}},
                    {{left: '\\\\[', right: '\\\\]', display: true}},
                    {{left: '\\\\(', right: '\\\\)', display: false}}
                ]
            }});
        }}
    </script>
</body>
</html>"#,
            title,
            self.config.css_url,
            self.config.js_url,
            html_body
        )
    }
    
    /// 更新配置
    pub fn update_config(&mut self, config: KatexConfig) {
        self.config = config;
    }
}

/// Markdown 数学扩展渲染器
pub struct MathMarkdownRenderer {
    math_renderer: MathRenderer,
}

impl MathMarkdownRenderer {
    /// 创建渲染器
    pub fn new() -> Result<Self> {
        let math_renderer = MathRenderer::new(KatexConfig::default())?;
        Ok(Self { math_renderer })
    }
    
    /// 渲染带数学公式的 Markdown
    pub fn render(&self, markdown: &str) -> Result<String> {
        let html = self.math_renderer.generate_html(markdown, "Math Document");
        Ok(html)
    }
    
    /// 提取所有公式
    pub fn extract_formulas(&self, markdown: &str) -> Vec<MathFormula> {
        self.math_renderer.extract_formulas(markdown)
    }
}

impl Default for MathMarkdownRenderer {
    fn default() -> Self {
        Self::new().expect("Failed to create MathMarkdownRenderer")
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_math_renderer_creation() {
        let renderer = MathRenderer::new(KatexConfig::default());
        assert!(renderer.is_ok());
    }
    
    #[test]
    fn test_extract_formulas() {
        let renderer = MathRenderer::new(KatexConfig::default()).unwrap();
        let markdown = r#"
# 数学公式示例

行内公式：$E = mc^2$

块级公式：
$$
\int_{0}^{\infty} e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
$$
"#;
        
        let formulas = renderer.extract_formulas(markdown);
        assert_eq!(formulas.len(), 2);
        
        // 检查行内公式
        let inline = formulas.iter().find(|f| f.math_type == MathType::Inline);
        assert!(inline.is_some());
        assert!(inline.unwrap().latex.contains("E = mc"));
        
        // 检查块级公式
        let display = formulas.iter().find(|f| f.math_type == MathType::Display);
        assert!(display.is_some());
        assert!(display.unwrap().latex.contains("int"));
    }
    
    #[test]
    fn test_render_markdown() {
        let renderer = MathRenderer::new(KatexConfig::default()).unwrap();
        let markdown = "这是 $x^2$ 公式";
        
        let rendered = renderer.render_markdown(markdown);
        assert!(rendered.contains("katex"));
        assert!(rendered.contains("x^2"));
    }
    
    #[test]
    fn test_math_markdown_renderer() {
        let renderer = MathMarkdownRenderer::default();
        let markdown = r#"
# 测试

$$
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
$$
"#;
        
        let html = renderer.render(markdown);
        assert!(html.is_ok());
        
        let html_content = html.unwrap();
        assert!(html_content.contains("katex.min.css"));
        assert!(html_content.contains("katex.min.js"));
    }
}
