"""
Markdown 转 PDF 转换器

自动化将 Markdown 文件转换为 PDF，支持:
- 中文字体渲染
- 图片嵌入（相对路径自动处理）
- 自定义 CSS 样式
- 批量转换
"""

import os
import re
from pathlib import Path
from typing import Optional, List
import markdown
from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration


class PDFConverter:
    """Markdown 转 PDF 转换器"""
    
    # 默认 CSS 样式 - 优化的中文排版
    DEFAULT_CSS = """
        @page {
            size: A4;
            margin: 2cm;
        }
        
        body {
            font-family: "PingFang SC", "Microsoft YaHei", "SimHei", "Hiragino Sans GB", sans-serif;
            line-height: 1.8;
            color: #333;
            font-size: 11pt;
        }
        
        h1 {
            color: #2c3e50;
            border-bottom: 3px solid #3498db;
            padding-bottom: 10px;
            margin-top: 30px;
            margin-bottom: 20px;
            font-size: 24pt;
        }
        
        h2 {
            color: #34495e;
            margin-top: 30px;
            margin-bottom: 15px;
            border-left: 5px solid #3498db;
            padding-left: 15px;
            font-size: 18pt;
        }
        
        h3 {
            color: #555;
            margin-top: 20px;
            margin-bottom: 10px;
            font-size: 14pt;
        }
        
        h4, h5, h6 {
            color: #666;
            margin-top: 15px;
            margin-bottom: 10px;
        }
        
        p {
            margin-bottom: 12px;
            text-align: justify;
        }
        
        strong {
            color: #e74c3c;
            font-weight: bold;
        }
        
        em {
            font-style: italic;
            color: #555;
        }
        
        ul, ol {
            margin-left: 20px;
            margin-bottom: 15px;
        }
        
        li {
            margin-bottom: 8px;
            line-height: 1.6;
        }
        
        img {
            max-width: 100%;
            display: block;
            margin: 20px auto;
            border: 1px solid #ddd;
            border-radius: 5px;
            page-break-inside: avoid;
        }
        
        code {
            background: #f4f4f4;
            padding: 2px 6px;
            border-radius: 3px;
            font-family: "Monaco", "Menlo", "Consolas", monospace;
            font-size: 9pt;
        }
        
        pre {
            background: #f8f8f8;
            padding: 15px;
            border-radius: 5px;
            border-left: 4px solid #3498db;
            overflow-x: auto;
            margin-bottom: 20px;
            page-break-inside: avoid;
        }
        
        pre code {
            background: none;
            padding: 0;
        }
        
        blockquote {
            border-left: 4px solid #ddd;
            padding-left: 15px;
            margin-left: 0;
            color: #666;
            font-style: italic;
        }
        
        table {
            border-collapse: collapse;
            width: 100%;
            margin-bottom: 20px;
            page-break-inside: avoid;
        }
        
        th, td {
            border: 1px solid #ddd;
            padding: 8px 12px;
            text-align: left;
        }
        
        th {
            background-color: #f2f2f2;
            font-weight: bold;
        }
        
        hr {
            border: none;
            border-top: 2px dashed #ddd;
            margin: 30px 0;
        }
        
        a {
            color: #3498db;
            text-decoration: none;
        }
        
        a:hover {
            text-decoration: underline;
        }
    """
    
    def __init__(self, custom_css: Optional[str] = None):
        """
        初始化转换器
        
        Args:
            custom_css: 自定义 CSS 样式，如果为 None 则使用默认样式
        """
        self.css = custom_css or self.DEFAULT_CSS
        self.font_config = FontConfiguration()
    
    def convert_markdown_to_pdf(
        self, 
        markdown_path: str,
        output_path: Optional[str] = None,
        verbose: bool = True
    ) -> str:
        """
        将 Markdown 文件转换为 PDF
        
        Args:
            markdown_path: Markdown 文件路径
            output_path: PDF 输出路径，如果为 None 则自动生成
            verbose: 是否显示详细信息
            
        Returns:
            生成的 PDF 文件路径
            
        Raises:
            FileNotFoundError: Markdown 文件不存在
            Exception: 转换过程中的其他错误
        """
        # 验证输入文件
        md_path = Path(markdown_path)
        if not md_path.exists():
            raise FileNotFoundError(f"Markdown 文件不存在: {markdown_path}")
        
        if verbose:
            print(f"📄 正在转换: {md_path.name}")
        
        # 确定输出路径
        if output_path is None:
            output_path = md_path.with_suffix('.pdf')
        else:
            output_path = Path(output_path)
        
        # 创建输出目录
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            # 1. 读取 Markdown 内容
            with open(md_path, 'r', encoding='utf-8') as f:
                md_content = f.read()
            
            # 2. 处理图片相对路径
            md_content = self._resolve_image_paths(md_content, md_path.parent)
            
            # 3. 转换为 HTML
            html_content = self._parse_markdown(md_content)
            
            # 4. 应用样式
            html_full = self._apply_styles(html_content)
            
            # 5. 生成 PDF
            self._generate_pdf(html_full, output_path)
            
            if verbose:
                file_size = output_path.stat().st_size / 1024
                print(f"✅ PDF 已生成: {output_path}")
                print(f"📊 文件大小: {file_size:.1f} KB")
            
            return str(output_path)
            
        except Exception as e:
            if verbose:
                print(f"❌ 转换失败: {str(e)}")
            raise
    
    def batch_convert(
        self,
        directory: str,
        recursive: bool = False,
        output_dir: Optional[str] = None,
        verbose: bool = True
    ) -> List[str]:
        """
        批量转换目录下的 Markdown 文件
        
        Args:
            directory: 要扫描的目录
            recursive: 是否递归处理子目录
            output_dir: 输出目录，如果为 None 则在原地生成
            verbose: 是否显示详细信息
            
        Returns:
            成功转换的 PDF 文件路径列表
        """
        dir_path = Path(directory)
        if not dir_path.exists():
            raise FileNotFoundError(f"目录不存在: {directory}")
        
        # 查找所有 Markdown 文件
        pattern = '**/*.md' if recursive else '*.md'
        md_files = list(dir_path.glob(pattern))
        
        if not md_files:
            if verbose:
                print(f"⚠️  未找到 Markdown 文件: {directory}")
            return []
        
        if verbose:
            print(f"🔍 找到 {len(md_files)} 个 Markdown 文件")
            print()
        
        # 批量转换
        success_files = []
        failed_files = []
        
        for i, md_file in enumerate(md_files, 1):
            try:
                if verbose:
                    print(f"[{i}/{len(md_files)}] ", end='')
                
                # 确定输出路径
                if output_dir:
                    output_path = Path(output_dir) / md_file.with_suffix('.pdf').name
                else:
                    output_path = None
                
                # 转换
                pdf_path = self.convert_markdown_to_pdf(
                    str(md_file),
                    str(output_path) if output_path else None,
                    verbose=verbose
                )
                success_files.append(pdf_path)
                
                if verbose:
                    print()
                
            except Exception as e:
                failed_files.append((str(md_file), str(e)))
                if verbose:
                    print(f"⚠️  跳过: {md_file.name} (原因: {str(e)})")
                    print()
        
        # 总结
        if verbose:
            print("-" * 50)
            print(f"✅ 成功转换: {len(success_files)} 个文件")
            if failed_files:
                print(f"❌ 失败: {len(failed_files)} 个文件")
                for file, error in failed_files:
                    print(f"   - {Path(file).name}: {error}")
        
        return success_files
    
    def _parse_markdown(self, md_content: str) -> str:
        """
        将 Markdown 转换为 HTML
        
        Args:
            md_content: Markdown 文本
            
        Returns:
            HTML 内容
        """
        html = markdown.markdown(
            md_content,
            extensions=[
                'extra',        # 表格、脚注等扩展语法
                'codehilite',   # 代码高亮
                'toc',          # 目录
                'attr_list',    # 属性支持（如图片宽度）
                'nl2br',        # 换行转换
            ],
            extension_configs={
                'codehilite': {
                    'css_class': 'highlight',
                    'linenums': False,
                }
            }
        )
        return html
    
    def _resolve_image_paths(self, md_content: str, base_dir: Path) -> str:
        """
        将 Markdown 中的相对路径图片转换为绝对路径
        
        Args:
            md_content: Markdown 内容
            base_dir: Markdown 文件所在目录
            
        Returns:
            处理后的 Markdown 内容
        """
        # 处理 HTML img 标签: <img src="path/to/image.jpg" />
        def replace_html_img(match):
            src = match.group(1)
            if not src.startswith(('http://', 'https://', '/')):
                abs_path = (base_dir / src).resolve()
                if abs_path.exists():
                    return f'<img src="file://{abs_path}"'
                else:
                    print(f"⚠️  图片不存在: {src}")
            return match.group(0)
        
        md_content = re.sub(
            r'<img\s+src=["\']([^"\']+)["\']',
            replace_html_img,
            md_content
        )
        
        # 处理 Markdown 图片语法: ![alt](path/to/image.jpg)
        def replace_md_img(match):
            alt = match.group(1)
            src = match.group(2)
            if not src.startswith(('http://', 'https://', '/')):
                abs_path = (base_dir / src).resolve()
                if abs_path.exists():
                    return f'![{alt}](file://{abs_path})'
                else:
                    print(f"⚠️  图片不存在: {src}")
            return match.group(0)
        
        md_content = re.sub(
            r'!\[([^\]]*)\]\(([^)]+)\)',
            replace_md_img,
            md_content
        )
        
        return md_content
    
    def _apply_styles(self, html_content: str) -> str:
        """
        将 HTML 内容包装为完整的 HTML 文档并应用样式
        
        Args:
            html_content: HTML 内容
            
        Returns:
            完整的 HTML 文档
        """
        html_full = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        {self.css}
    </style>
</head>
<body>
{html_content}
</body>
</html>
"""
        return html_full
    
    def _generate_pdf(self, html_content: str, output_path: Path):
        """
        使用 WeasyPrint 生成 PDF
        
        Args:
            html_content: 完整的 HTML 文档
            output_path: PDF 输出路径
        """
        html = HTML(string=html_content)
        css = CSS(string=self.css, font_config=self.font_config)
        html.write_pdf(
            output_path,
            stylesheets=[css],
            font_config=self.font_config
        )
