# 结构化语料数据模型
# HLDP://tools/notion-corpus-loader/structure

from dataclasses import dataclass, field
from typing import List, Dict, Optional
import json

@dataclass
class StructuredCorpusItem:
    source_id: str = ""
    source_type: str = ""
    hldp_path: str = ""
    title: str = ""
    blocks: List[Dict] = field(default_factory=list)
    raw_text: str = ""
    cognitive_jumps: List[str] = field(default_factory=list)
    causal_chains: List[str] = field(default_factory=list)
    persona: str = ""
    quality_score: float = 0.5
    quality_tags: List[str] = field(default_factory=list)
    created_time: str = ""
    last_edited_time: str = ""
    metadata: Dict = field(default_factory=dict)
    
    def to_training_sample(self, format: str = "text") -> str:
        if format == "text": return self._to_text_sample()
        elif format == "chat": return self._to_chat_sample()
        return self._to_text_sample()
    
    def _to_text_sample(self) -> str:
        parts = []
        if self.hldp_path: parts.append(f"[HLDP_PATH]{self.hldp_path}[/HLDP_PATH]")
        if self.persona: parts.append(f"[PERSONA]{self.persona}[/PERSONA]")
        if self.title: parts.append(f"[TITLE]{self.title}[/TITLE]")
        for jump in self.cognitive_jumps[:3]: parts.append(f"[COGNITIVE_JUMP]{jump}[/COGNITIVE_JUMP]")
        for chain in self.causal_chains[:3]: parts.append(f"[CAUSAL_CHAIN]{chain}[/CAUSAL_CHAIN]")
        if self.quality_score > 0.7: parts.append("[QUALITY_HIGH]")
        elif self.quality_score > 0.4: parts.append("[QUALITY_MEDIUM]")
        parts.append("[CONTENT]")
        for block in self.blocks[:50]:
            bt = block.get('type','paragraph'); c = block.get('content','')
            if c: parts.append(f"[{bt.upper()}]{c}[/{bt.upper()}]")
        parts.append("[/CONTENT]")
        return '\n'.join(parts)
    
    def _to_chat_sample(self) -> str:
        parts = []
        if self.persona: parts.append(f"[PERSONA]{self.persona}[/PERSONA]")
        parts.append("[THINKING]")
        for block in self.blocks[:30]:
            c = block.get('content','')
            if c: parts.append(c[:200])
        parts.append("[/THINKING]")
        return '\n'.join(parts)
    
    def estimate_tokens(self) -> int:
        cc = sum(1 for c in self.raw_text if '\u4e00' <= c <= '\u9fff')
        tc = len(self.raw_text)
        return int(cc * 1.5 + (tc - cc) * 0.75)

@dataclass
class CorpusCollection:
    items: List[StructuredCorpusItem] = field(default_factory=list)
    total_tokens: int = 0
    persona_distribution: Dict[str, int] = field(default_factory=dict)
    
    def add(self, item: StructuredCorpusItem):
        self.items.append(item)
        t = item.estimate_tokens()
        self.total_tokens += t
        p = item.persona or "unknown"
        self.persona_distribution[p] = self.persona_distribution.get(p,0) + t
    
    def summary(self) -> str:
        total = self.total_tokens
        s = f"{total/1e8:.2f}亿" if total > 1e8 else (f"{total/1e4:.1f}万" if total > 1e4 else str(total))
        lines = [f"条目: {len(self.items)}", f"总token: {s}", f"分布:"]
        for p, t in sorted(self.persona_distribution.items(), key=lambda x:-x[1]):
            pct = t/total*100 if total else 0
            lines.append(f"  {p}: {t/1e4:.1f}万 ({pct:.1f}%)")
        jc = sum(1 for i in self.items if i.cognitive_jumps)
        lines.append(f"含跃迁标注: {jc}/{len(self.items)}")
        return '\n'.join(lines)
    
    def to_jsonl(self, fp: str, fmt: str = "text"):
        with open(fp,'w',encoding='utf-8') as f:
            for item in self.items:
                f.write(json.dumps({"text":item.to_training_sample(fmt),"metadata":{"source_id":item.source_id,"hldp_path":item.hldp_path,"persona":item.persona,"quality_score":item.quality_score,"tokens_estimate":item.estimate_tokens()}},ensure_ascii=False)+'\n')
