"""
管线与门面骨架

这里只给出基于抽象接口的骨架实现，不绑定任何具体底层实现。
实际使用时，可以在其它模块中提供具体的 TOCExtractor / HierarchyClassifier
/ FullTextExtractor / TextSplitter / ResultWriter 实现，并通过依赖注入组装。
"""

from __future__ import annotations

import asyncio
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Optional

from .interfaces import (
    ConfigProvider,
    DocumentPipeline,
    DocumentSource,
    FileParseFacade,
    FullTextExtractor,
    HierarchyClassifier,
    ResultWriter,
    TOCExtractor,
    TextSplitter,
)


@dataclass
class PipelineComponents:
    """组装流水线所需的各个组件接口。"""

    config: ConfigProvider
    toc_extractor: TOCExtractor
    classifier: HierarchyClassifier
    fulltext_extractor: FullTextExtractor
    splitter: TextSplitter
    writers: List[ResultWriter]
    chunk_classifier: Optional[object] = None  # ChunkClassifier，可选


class DefaultDocumentPipeline(DocumentPipeline):
    """
    一个基于接口的默认流水线骨架。

    注意：这里只是流程编排示例，不做任何实现细节假设。
    """

    def __init__(self, components: PipelineComponents) -> None:
        self._c = components

    async def run_async(
        self,
        source: DocumentSource,
        target_level: Optional[int] = None,
        max_chunk_size: Optional[int] = None,
        min_chunk_size: Optional[int] = None,
        output_dir: Optional[str | Path] = None,
    ) -> Dict[str, object]:
        """异步版流水线执行（支持并发优化）"""
        cfg = self._c.config

        # 读取默认配置（具体 key 由实现方自行约定）
        if target_level is None:
            target_level = int(cfg.get("text_splitting.target_level", 1))
        if max_chunk_size is None:
            max_chunk_size = int(cfg.get("text_splitting.max_chunk_size", 3000))
        if min_chunk_size is None:
            min_chunk_size = int(cfg.get("text_splitting.min_chunk_size", 50))

        # 1. 提取目录
        toc_info = self._c.toc_extractor.extract_toc(source)

        # 2. 目录分类（使用异步接口）
        if hasattr(self._c.classifier, 'classify_async'):
            classification = await self._c.classifier.classify_async(
                toc_info.get("toc_items", []),
                target_level=target_level,
            )
        else:
            classification = self._c.classifier.classify(
                toc_info.get("toc_items", []),
                target_level=target_level,
            )

        # 3. 提取全文
        pages_content = self._c.fulltext_extractor.extract_full_text(source)

        # 4. 按层级切分
        chunks = self._c.splitter.split_by_hierarchy(
            classification_items=classification.get("items", []),
            pages_content=pages_content,
            toc_info=toc_info,
            target_level=target_level,
            max_chunk_size=max_chunk_size,
            min_chunk_size=min_chunk_size,
        )

        # 5. 对chunks进行二级和三级分类（如果配置了chunk_classifier）
        if self._c.chunk_classifier is not None:
            try:
                # 二级分类（异步并发）
                chunks = await self._c.chunk_classifier.classify_chunks_secondary_async(chunks)
                # 三级分类（异步并发，内部使用增强型分类器）
                chunks = await self._c.chunk_classifier.classify_chunks_tertiary_async(chunks)
            except Exception as e:
                print(f"  警告: Chunk分类失败: {e}")

        result: Dict[str, object] = {
            "source": source,
            "toc_info": toc_info,
            "classification": classification,
            "chunks": chunks,
            "meta": {
                "target_level": target_level,
                "max_chunk_size": max_chunk_size,
                "min_chunk_size": min_chunk_size,
                "output_dir": str(output_dir) if output_dir else None,
            },
        }

        # 6. 写出结果（可以有多个 writer）
        for writer in self._c.writers:
            writer.write(result)

        return result

    def run(
        self,
        source: DocumentSource,
        target_level: Optional[int] = None,
        max_chunk_size: Optional[int] = None,
        min_chunk_size: Optional[int] = None,
        output_dir: Optional[str | Path] = None,
    ) -> Dict[str, object]:
        """同步版流水线执行（包装异步版本）"""
        try:
            return asyncio.run(self.run_async(
                source=source,
                target_level=target_level,
                max_chunk_size=max_chunk_size,
                min_chunk_size=min_chunk_size,
                output_dir=output_dir,
            ))
        except RuntimeError as e:
            if "cannot be called from a running event loop" in str(e):
                # 如果已经在事件循环中，创建新任务执行
                loop = asyncio.get_event_loop()
                return loop.run_until_complete(self.run_async(
                    source=source,
                    target_level=target_level,
                    max_chunk_size=max_chunk_size,
                    min_chunk_size=min_chunk_size,
                    output_dir=output_dir,
                ))
            raise


class DefaultFileParseFacade(FileParseFacade):
    """
    对外统一入口骨架。

    - 封装 DocumentSource 的创建；
    - 委托 DocumentPipeline 完成具体处理。
    """

    def __init__(self, pipeline: DocumentPipeline) -> None:
        self._pipeline = pipeline

    def process_file(
        self,
        file_path: str | Path,
        target_level: Optional[int] = None,
        max_chunk_size: Optional[int] = None,
        min_chunk_size: Optional[int] = None,
        output_dir: Optional[str | Path] = None,
    ) -> Dict[str, object]:
        path = Path(file_path)

        # 这里只构造最简单的 DocumentSource，真正的实现可以扩展为 bytes 流等
        source = DocumentSource(
            path=path,
            content=None,
            file_type=path.suffix.lstrip(".").lower() or None,
        )

        return self._pipeline.run(
            source=source,
            target_level=target_level,
            max_chunk_size=max_chunk_size,
            min_chunk_size=min_chunk_size,
            output_dir=output_dir,
        )


