//! 代码阅读器模块
//! 
//! 支持语法高亮、代码折叠、行号显示等功能

use anyhow::Result;
use serde::{Deserialize, Serialize};
use syntect::easy::HighlightLines;
use syntect::highlighting::{ThemeSet, Style};
use syntect::parsing::SyntaxSet;
use syntect::html::{styled_line_to_highlighted_html, IncludeBackground};

/// 代码语言
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum CodeLanguage {
    Rust,
    JavaScript,
    TypeScript,
    Python,
    Go,
    Java,
    C,
    Cpp,
    CSharp,
    Ruby,
    Swift,
    Kotlin,
    Scala,
    Shell,
    Sql,
    Html,
    Css,
    Json,
    Yaml,
    Xml,
    Markdown,
    Unknown,
}

impl CodeLanguage {
    /// 从文件扩展名判断语言
    pub fn from_extension(ext: &str) -> Self {
        match ext.to_lowercase().as_str() {
            "rs" => CodeLanguage::Rust,
            "js" | "mjs" | "cjs" => CodeLanguage::JavaScript,
            "ts" | "tsx" => CodeLanguage::TypeScript,
            "py" | "pyw" => CodeLanguage::Python,
            "go" => CodeLanguage::Go,
            "java" => CodeLanguage::Java,
            "c" | "h" => CodeLanguage::C,
            "cpp" | "cc" | "cxx" | "hpp" => CodeLanguage::Cpp,
            "cs" => CodeLanguage::CSharp,
            "rb" => CodeLanguage::Ruby,
            "swift" => CodeLanguage::Swift,
            "kt" | "kts" => CodeLanguage::Kotlin,
            "scala" | "sc" => CodeLanguage::Scala,
            "sh" | "bash" | "zsh" | "fish" => CodeLanguage::Shell,
            "sql" => CodeLanguage::Sql,
            "html" | "htm" => CodeLanguage::Html,
            "css" | "scss" | "sass" | "less" => CodeLanguage::Css,
            "json" => CodeLanguage::Json,
            "yaml" | "yml" => CodeLanguage::Yaml,
            "xml" | "svg" => CodeLanguage::Xml,
            "md" | "markdown" => CodeLanguage::Markdown,
            _ => CodeLanguage::Unknown,
        }
    }
    
    /// 获取 syntect 语法名称
    pub fn to_syntect_name(&self) -> &'static str {
        match self {
            CodeLanguage::Rust => "Rust",
            CodeLanguage::JavaScript => "JavaScript",
            CodeLanguage::TypeScript => "TypeScript",
            CodeLanguage::Python => "Python",
            CodeLanguage::Go => "Go",
            CodeLanguage::Java => "Java",
            CodeLanguage::C => "C",
            CodeLanguage::Cpp => "C++",
            CodeLanguage::CSharp => "C#",
            CodeLanguage::Ruby => "Ruby",
            CodeLanguage::Swift => "Swift",
            CodeLanguage::Kotlin => "Kotlin",
            CodeLanguage::Scala => "Scala",
            CodeLanguage::Shell => "Bash (shell)",
            CodeLanguage::Sql => "SQL",
            CodeLanguage::Html => "HTML",
            CodeLanguage::Css => "CSS",
            CodeLanguage::Json => "JSON",
            CodeLanguage::Yaml => "YAML",
            CodeLanguage::Xml => "XML",
            CodeLanguage::Markdown => "Markdown",
            CodeLanguage::Unknown => "Plain Text",
        }
    }
    
    /// 获取语言显示名称
    pub fn display_name(&self) -> &'static str {
        match self {
            CodeLanguage::Rust => "Rust",
            CodeLanguage::JavaScript => "JavaScript",
            CodeLanguage::TypeScript => "TypeScript",
            CodeLanguage::Python => "Python",
            CodeLanguage::Go => "Go",
            CodeLanguage::Java => "Java",
            CodeLanguage::C => "C",
            CodeLanguage::Cpp => "C++",
            CodeLanguage::CSharp => "C#",
            CodeLanguage::Ruby => "Ruby",
            CodeLanguage::Swift => "Swift",
            CodeLanguage::Kotlin => "Kotlin",
            CodeLanguage::Scala => "Scala",
            CodeLanguage::Shell => "Shell",
            CodeLanguage::Sql => "SQL",
            CodeLanguage::Html => "HTML",
            CodeLanguage::Css => "CSS",
            CodeLanguage::Json => "JSON",
            CodeLanguage::Yaml => "YAML",
            CodeLanguage::Xml => "XML",
            CodeLanguage::Markdown => "Markdown",
            CodeLanguage::Unknown => "Unknown",
        }
    }
}

/// 代码行
#[derive(Debug, Clone, PartialEq)]
pub struct CodeLine {
    pub number: usize,
    pub content: String,
    pub highlighted_html: String,
    pub is_folded: bool,
}

/// 代码文档
#[derive(Debug, Clone, PartialEq)]
pub struct CodeDocument {
    pub title: String,
    pub path: String,
    pub language: CodeLanguage,
    pub lines: Vec<CodeLine>,
    pub total_lines: usize,
}

/// 代码阅读器
pub struct CodeReader {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

impl CodeReader {
    /// 创建代码阅读器
    pub fn new() -> Result<Self> {
        // 使用内置的语法和主题
        let syntax_set = SyntaxSet::load_defaults_newlines();
        let theme_set = ThemeSet::load_defaults();
        
        Ok(Self {
            syntax_set,
            theme_set,
        })
    }
    
    /// 解析代码文件
    pub fn parse(&self, path: &str, content: &str) -> Result<CodeDocument> {
        let path_obj = std::path::Path::new(path);
        let ext = path_obj.extension()
            .and_then(|e| e.to_str())
            .unwrap_or("");
        
        let language = CodeLanguage::from_extension(ext);
        let title = path_obj.file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("Untitled")
            .to_string();
        
        let lines = self.highlight_code(content, &language);
        let total_lines = lines.len();
        
        Ok(CodeDocument {
            title,
            path: path.to_string(),
            language,
            lines,
            total_lines,
        })
    }
    
    /// 语法高亮
    fn highlight_code(&self, code: &str, language: &CodeLanguage) -> Vec<CodeLine> {
        let syntax = self.syntax_set
            .find_syntax_by_name(language.to_syntect_name())
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
        
        let theme = &self.theme_set.themes["base16-ocean.dark"];
        let mut highlighter = HighlightLines::new(syntax, theme);
        
        let mut lines = Vec::new();
        
        for (index, line) in code.lines().enumerate() {
            let line_number = index + 1;
            
            // 语法高亮
            let ranges = highlighter.highlight_line(line, &self.syntax_set)
                .unwrap_or_else(|_| vec![]);
            
            // 转换为 HTML
            let html = styled_line_to_highlighted_html(
                &ranges[..],
                IncludeBackground::No
            ).unwrap_or_else(|_| line.to_string());
            
            lines.push(CodeLine {
                number: line_number,
                content: line.to_string(),
                highlighted_html: html,
                is_folded: false,
            });
        }
        
        lines
    }
    
    /// 渲染代码文档为 HTML
    pub fn render(&self, doc: &CodeDocument) -> Result<String> {
        let mut html = String::new();
        
        html.push_str("<!DOCTYPE html>\n<html>\n<head>\n");
        html.push_str("<meta charset=\"UTF-8\">\n");
        html.push_str(&format!("<title>{}</title>\n", doc.title));
        html.push_str("<style>\n");
        html.push_str(Self::get_code_css(&doc.language));
        html.push_str("</style>\n</head>\n<body>\n");
        
        html.push_str("<div class=\"code-container\">\n");
        
        // 语言标识
        html.push_str(&format!(
            "<div class=\"code-header\">\n  <span class=\"language-badge\">{}</span>\n  <span class=\"line-count\">{} lines</span>\n</div>\n",
            doc.language.display_name(),
            doc.total_lines
        ));
        
        // 代码内容
        html.push_str("<pre class=\"code-content\"><code>\n");
        
        for line in &doc.lines {
            if line.is_folded {
                continue;
            }
            
            html.push_str(&format!(
                "<div class=\"code-line\" data-line=\"{}\">\n  <span class=\"line-number\">{}</span>\n  <span class=\"line-content\">{}</span>\n</div>\n",
                line.number,
                line.number,
                line.highlighted_html
            ));
        }
        
        html.push_str("</code></pre>\n");
        html.push_str("</div>\n");
        
        html.push_str("</body>\n</html>");
        
        Ok(html)
    }
    
    /// 获取代码样式
    fn get_code_css(language: &CodeLanguage) -> &'static str {
        r#"
:root {
    --bg-primary: #1a1a2e;
    --bg-secondary: #16213e;
    --bg-line-number: #0f3460;
    --text-primary: #eaeaea;
    --text-muted: #6c757d;
    --border-color: #2a2a4a;
    --accent-color: #00adb5;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, monospace;
    font-size: 14px;
    line-height: 1.6;
    background-color: var(--bg-primary);
    color: var(--text-primary);
}
.code-container {
    max-width: 1200px;
    margin: 20px auto;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
}
.code-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 20px;
    background: var(--bg-line-number);
    border-bottom: 1px solid var(--border-color);
}
.language-badge {
    font-size: 12px;
    font-weight: 600;
    color: var(--accent-color);
    text-transform: uppercase;
}
.line-count {
    font-size: 12px;
    color: var(--text-muted);
}
.code-content {
    overflow-x: auto;
    padding: 0;
    margin: 0;
}
.code-line {
    display: flex;
    min-height: 1.6em;
}
.code-line:hover {
    background: rgba(255, 255, 255, 0.05);
}
.line-number {
    display: inline-block;
    width: 50px;
    padding: 0 10px;
    text-align: right;
    color: var(--text-muted);
    background: var(--bg-line-number);
    border-right: 1px solid var(--border-color);
    user-select: none;
    flex-shrink: 0;
}
.line-content {
    flex: 1;
    padding: 0 15px;
    white-space: pre;
}
/* 语法高亮颜色 */
.c { color: #6c757d; font-style: italic; }
.k { color: #ff79c6; font-weight: bold; }
.o { color: #ff79c6; }
.cm { color: #6c757d; font-style: italic; }
.kd { color: #ff79c6; font-weight: bold; }
.kn { color: #ff79c6; font-weight: bold; }
.kp { color: #ff79c6; font-weight: bold; }
.kr { color: #ff79c6; font-weight: bold; }
.kt { color: #8be9fd; font-style: italic; }
.n { color: #f8f8f2; }
.na { color: #50fa7b; }
.nb { color: #8be9fd; font-style: italic; }
.nc { color: #50fa7b; font-weight: bold; }
.no { color: #f1fa8c; }
.nd { color: #bd93f9; }
.ni { color: #f8f8f2; }
.ne { color: #50fa7b; font-weight: bold; }
.nf { color: #50fa7b; }
.nl { color: #8be9fd; font-style: italic; }
.nn { color: #f8f8f2; }
.nt { color: #ff79c6; }
.nv { color: #f8f8f2; }
.s { color: #f1fa8c; }
.s1 { color: #f1fa8c; }
.s2 { color: #f1fa8c; }
.se { color: #f1fa8c; }
.sh { color: #f1fa8c; }
.si { color: #f1fa8c; }
.sx { color: #f1fa8c; }
.m { color: #bd93f9; }
.mi { color: #bd93f9; }
.mf { color: #bd93f9; }
/* 滚动条 */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg-primary); }
::-webkit-scrollbar-thumb { background: var(--bg-line-number); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent-color); }
"#
    }
    
    /// 折叠代码行
    pub fn fold_lines(&mut self, doc: &mut CodeDocument, start: usize, end: usize) {
        for line in &mut doc.lines {
            if line.number >= start && line.number <= end {
                line.is_folded = true;
            }
        }
    }
    
    /// 搜索代码
    pub fn search(&self, doc: &CodeDocument, query: &str) -> Vec<usize> {
        let mut results = Vec::new();
        let query_lower = query.to_lowercase();
        
        for line in &doc.lines {
            if line.content.to_lowercase().contains(&query_lower) {
                results.push(line.number);
            }
        }
        
        results
    }
}

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

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_language_detection() {
        assert!(matches!(CodeLanguage::from_extension("rs"), CodeLanguage::Rust));
        assert!(matches!(CodeLanguage::from_extension("py"), CodeLanguage::Python));
        assert!(matches!(CodeLanguage::from_extension("unknown"), CodeLanguage::Unknown));
    }
    
    #[test]
    fn test_code_reader_creation() {
        let reader = CodeReader::new();
        assert!(reader.is_ok());
    }
}
