"""
MinerU 本地部署版本全文提取实现

使用本地部署的 MinerU 服务进行 OCR 识别
支持返回 HTML 格式自动转换为 Markdown
"""

from __future__ import annotations

import json
import os
import re
import requests
from pathlib import Path
from typing import Any, Dict, List, Optional

from foundation.observability.logger.loggering import review_logger as logger

from ..config.provider import default_config_provider
from ..interfaces import DocumentSource, FullTextExtractor

# 尝试导入 HTML 到 Markdown 转换器
try:
    from .html_to_markdown import convert_html_to_markdown, HTMLToMarkdownConverter
    HTML_CONVERTER_AVAILABLE = True
except ImportError:
    HTML_CONVERTER_AVAILABLE = False


class LocalMinerUFullTextExtractor(FullTextExtractor):
    """使用本地部署的 MinerU 提取 PDF 全文内容。"""

    def __init__(
        self,
        server_ip: Optional[str] = None,
        server_port: Optional[int] = None,
        api_key: Optional[str] = None,
        timeout: Optional[int] = None
    ) -> None:
        """
        初始化本地 MinerU 提取器。

        参数:
            server_ip: MinerU 服务器 IP（可选，默认从配置读取）
            server_port: MinerU 服务器端口（可选，默认从配置读取）
            api_key: 鉴权密钥（可选，默认从配置读取）
            timeout: 请求超时时间（可选，默认从配置读取）
        """
        self._cfg = default_config_provider

        # 从配置读取或使用传入参数
        self.server_ip = server_ip or self._cfg.get("mineru_local.server_ip", "127.0.0.1")
        self.server_port = server_port or self._cfg.get("mineru_local.server_port", 23424)
        self.api_key = api_key or self._cfg.get("mineru_local.api_key", "")
        self.timeout = timeout or self._cfg.get("mineru_local.timeout", 300)

        # 构建 API URL
        self.api_url = f"http://{self.server_ip}:{self.server_port}/file_parse"

    def extract_full_text(self, source: DocumentSource) -> List[Dict[str, Any]]:
        """
        使用本地 MinerU API 提取全文。

        流程：
        1. 直接上传文件到本地 MinerU 服务
        2. 获取解析结果
        """
        if source.path is None:
            raise ValueError("本地 MinerU API 目前仅支持文件路径输入 (source.path)")

        file_path = str(source.path)

        # 构建请求头（必须包含 API-KEY）
        headers = {
            "API-KEY": self.api_key
        }

        try:
            logger.debug(f"正在请求本地 MinerU OCR 识别: {os.path.basename(file_path)}")

            # 准备要上传的文件
            with open(file_path, "rb") as f:
                files = {
                    "files": (os.path.basename(file_path), f)  # 字段名必须是 'files'（复数）
                }

                # 发送 POST 请求
                response = requests.post(
                    self.api_url,
                    headers=headers,
                    files=files,
                    timeout=self.timeout
                )

            # 检查请求是否成功，如果失败打印详细信息
            if response.status_code != 200:
                logger.error(f"[ERROR] MinerU returned HTTP {response.status_code}")
                try:
                    error_detail = response.json()
                    logger.error(f"[ERROR] Response: {error_detail}")
                except:
                    logger.error(f"[ERROR] Raw response: {response.text[:500]}")
            response.raise_for_status()

            # 解析结果
            result = response.json()
            logger.debug("[OK] Local MinerU OCR recognition successful!")

            # 提取 markdown 内容
            md_content = self._extract_markdown_from_result(result)

            if not md_content:
                logger.debug("警告: 本地 MinerU API 返回内容为空")

            # 将整个 Markdown 作为一个页面返回
            return [{
                "page_num": 1,
                "text": md_content,
                "start_pos": 0,
                "end_pos": len(md_content),
                "source_file": file_path
            }]

        except requests.exceptions.Timeout:
            logger.error(f"[FAIL] Request timeout: Local MinerU service no response after {self.timeout} seconds")
            raise
        except requests.exceptions.RequestException as e:
            logger.error(f"[FAIL] Request failed: {e}")
            raise
        except Exception as e:
            logger.error(f"[FAIL] Local MinerU extraction exception: {e}")
            raise

    def _extract_markdown_from_result(self, result: Dict[str, Any]) -> str:
        """
        从 MinerU 返回结果中提取 markdown 内容。
        
        支持自动检测 HTML 格式并转换为 Markdown。

        参数:
            result: MinerU API 返回的 JSON 数据

        返回:
            提取的 markdown 文本
        """
        raw_content = None
        content_source = None
        
        # 尝试多种可能的结果格式

        # 格式1: 直接返回 full_text 字段
        if "full_text" in result:
            raw_content = result["full_text"]
            content_source = "full_text"

        # 格式2: data.full_text
        elif "data" in result and isinstance(result["data"], dict):
            if "full_text" in result["data"]:
                raw_content = result["data"]["full_text"]
                content_source = "data.full_text"
            # 格式3: data.markdown
            elif "markdown" in result["data"]:
                raw_content = result["data"]["markdown"]
                content_source = "data.markdown"
            # 格式4: data.content
            elif "content" in result["data"]:
                raw_content = result["data"]["content"]
                content_source = "data.content"

        # 格式5: markdown 字段
        elif "markdown" in result:
            raw_content = result["markdown"]
            content_source = "markdown"

        # 格式6: content 字段
        elif "content" in result:
            raw_content = result["content"]
            content_source = "content"

        # 格式7: 遍历 pages 提取内容
        elif "pages" in result:
            pages_text = []
            for page in result["pages"]:
                if isinstance(page, dict):
                    if "markdown" in page:
                        pages_text.append(page["markdown"])
                    elif "text" in page:
                        pages_text.append(page["text"])
                    elif "content" in page:
                        pages_text.append(page["content"])
            if pages_text:
                raw_content = "\n\n".join(pages_text)
                content_source = "pages"

        # 格式8: 本地 MinerU API 格式
        # {"results": {"filename": {"md_content": "..."}}}
        elif "results" in result and isinstance(result["results"], dict):
            for filename, file_data in result["results"].items():
                if isinstance(file_data, dict) and "md_content" in file_data:
                    raw_content = file_data["md_content"]
                    content_source = "results.md_content"
                    break

        # 格式9: results 列表
        elif "results" in result and isinstance(result["results"], list):
            texts = []
            for item in result["results"]:
                if isinstance(item, dict):
                    if "full_text" in item:
                        texts.append(item["full_text"])
                    elif "markdown" in item:
                        texts.append(item["markdown"])
                    elif "text" in item:
                        texts.append(item["text"])
            if texts:
                raw_content = "\n\n".join(texts)
                content_source = "results.list"

        # 如果都没找到，打印原始结果用于调试
        if raw_content is None:
            logger.debug("警告: 无法从 MinerU 结果中提取内容，返回空字符串")
            logger.debug(f"结果结构: {list(result.keys())}")
            return ""
        
        # 检测并转换 HTML 格式
        if raw_content and self._is_html_content(raw_content):
            logger.debug(f"[INFO] 检测到 HTML 格式内容（来源: {content_source}），自动转换为 Markdown")
            raw_content = self._convert_html_to_markdown(raw_content)
        
        return raw_content
    
    def _is_html_content(self, content: str) -> bool:
        """
        检测内容是否为 HTML 格式
        
        通过检查是否包含常见的 HTML 标签来判断
        """
        if not content or not isinstance(content, str):
            return False
        
        # 检查是否包含常见的 HTML 标签
        html_tags_pattern = r'<(?:html|head|body|div|span|p|br|hr|table|tr|td|th|ul|ol|li|h[1-6]|b|i|em|strong|a|img|meta|title|link|script|style)[^>]*>'
        
        # 如果找到多个 HTML 标签，认为是 HTML 内容
        matches = re.findall(html_tags_pattern, content, re.IGNORECASE)
        
        # 至少找到 2 个 HTML 标签才认为是 HTML（减少误判）
        return len(matches) >= 2
    
    def _convert_html_to_markdown(self, html_content: str) -> str:
        """
        将 HTML 内容转换为 Markdown
        
        如果安装了 markdownify 则使用，否则使用简单降级方案
        """
        if HTML_CONVERTER_AVAILABLE:
            try:
                return convert_html_to_markdown(html_content)
            except Exception as e:
                logger.error(f"[WARN] HTML 转 Markdown 失败: {e}，使用降级方案")
                return self._simple_html_to_text(html_content)
        else:
            logger.debug("[WARN] HTML 转换器不可用，使用简单文本提取")
            return self._simple_html_to_text(html_content)
    
    def _simple_html_to_text(self, html_content: str) -> str:
        """
        简单的 HTML 到文本转换（降级方案）
        """
        if not html_content:
            return ""
        
        # 移除 script 和 style 标签及其内容
        text = re.sub(r'<script[^>]*>.*?</script>', '', html_content, flags=re.DOTALL | re.IGNORECASE)
        text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL | re.IGNORECASE)
        
        # 将常见块级标签转为换行
        text = re.sub(r'<br\s*/?>', '\n', text, flags=re.IGNORECASE)
        text = re.sub(r'</p>', '\n\n', text, flags=re.IGNORECASE)
        text = re.sub(r'</div>', '\n', text, flags=re.IGNORECASE)
        text = re.sub(r'</tr>', '\n', text, flags=re.IGNORECASE)
        text = re.sub(r'</td>', ' ', text, flags=re.IGNORECASE)
        text = re.sub(r'</th>', ' ', text, flags=re.IGNORECASE)
        
        # 处理标题标签
        for i in range(6, 0, -1):
            text = re.sub(rf'<h{i}[^>]*>(.*?)</h{i}>', rf'{"#" * i} \1\n\n', text, flags=re.IGNORECASE | re.DOTALL)
        
        # 剥离所有剩余的 HTML 标签
        text = re.sub(r'<[^>]+>', '', text)
        
        # 清理 HTML 实体
        text = text.replace('&nbsp;', ' ')
        text = text.replace('&lt;', '<')
        text = text.replace('&gt;', '>')
        text = text.replace('&amp;', '&')
        text = text.replace('&quot;', '"')
        text = text.replace('&#39;', "'")
        
        # 清理多余空行
        text = re.sub(r'\n{3,}', '\n\n', text)
        
        return text.strip()
