from pydantic import BaseModel
from typing import Optional, List, Dict, Literal
from enum import Enum

# Language type for prompts
LanguageType = Literal["zh", "en"]


class AttributeNode(BaseModel):
    name: str
    category: Optional[str] = None  # 材料, 功能, 用途, 使用族群
    children: Optional[List["AttributeNode"]] = None


AttributeNode.model_rebuild()


class AnalyzeRequest(BaseModel):
    query: str
    model: Optional[str] = None
    temperature: Optional[float] = 0.7
    categories: Optional[List[str]] = None  # 如果為 None，使用預設類別


class AnalyzeResponse(BaseModel):
    query: str
    attributes: AttributeNode


class ModelListResponse(BaseModel):
    models: List[str]


# ===== Multi-step streaming schemas =====

class Step1Result(BaseModel):
    """Step 1 的結果：各類別屬性列表"""
    materials: List[str]
    functions: List[str]
    usages: List[str]
    users: List[str]


class CausalChain(BaseModel):
    """單條因果鏈"""
    material: str
    function: str
    usage: str
    user: str


class StreamAnalyzeRequest(BaseModel):
    """Multi-step analysis request (updated to support dynamic categories)"""
    query: str
    model: Optional[str] = None
    temperature: Optional[float] = 0.7
    chain_count: int = 5  # User can set how many causal chains to generate

    # Dynamic category support
    category_mode: Optional[str] = "dynamic_auto"  # CategoryMode enum value
    custom_categories: Optional[List[str]] = None
    suggested_category_count: int = 3  # Suggest LLM to generate this many categories

    # Language setting
    lang: LanguageType = "zh"


class StreamAnalyzeResponse(BaseModel):
    """最終完整結果"""
    query: str
    step1_result: Step1Result
    causal_chains: List[CausalChain]
    attributes: AttributeNode


# ===== Dynamic category system schemas =====

class CategoryMode(str, Enum):
    """類別模式"""
    FIXED_ONLY = "fixed_only"
    FIXED_PLUS_CUSTOM = "fixed_plus_custom"
    FIXED_PLUS_DYNAMIC = "fixed_plus_dynamic"  # Fixed + LLM suggested
    CUSTOM_ONLY = "custom_only"
    DYNAMIC_AUTO = "dynamic_auto"


class CategoryDefinition(BaseModel):
    """類別定義"""
    name: str
    description: Optional[str] = None
    is_fixed: bool = True  # LLM 生成的為 False
    order: int = 0


class Step0Result(BaseModel):
    """Step 0: LLM 分析建議類別"""
    categories: List[CategoryDefinition]


class DynamicStep1Result(BaseModel):
    """動態版本的 Step 1 結果"""
    attributes: Dict[str, List[str]]  # {類別名: [屬性列表]}


class DynamicCausalChain(BaseModel):
    """動態版本的因果鏈"""
    chain: Dict[str, str]  # {類別名: 選中屬性}


# ===== DAG (Directed Acyclic Graph) schemas =====

class DAGNode(BaseModel):
    """DAG 節點 - 每個屬性只出現一次"""
    id: str                    # 唯一 ID: "{category}_{index}"
    name: str                  # 顯示名稱
    category: str              # 所屬類別
    order: int                 # 欄位內位置


class DAGEdge(BaseModel):
    """DAG 邊 - 節點之間的連接"""
    source_id: str
    target_id: str


class AttributeDAG(BaseModel):
    """完整 DAG 結構"""
    query: str
    categories: List[CategoryDefinition]
    nodes: List[DAGNode]
    edges: List[DAGEdge]


class DAGRelationship(BaseModel):
    """Step 2 輸出 - 單一關係"""
    source_category: str
    source: str  # source attribute name
    target_category: str
    target: str  # target attribute name


# ===== Transformation Agent schemas =====

class TransformationRequest(BaseModel):
    """Transformation Agent request"""
    query: str                        # Original query (e.g., "bicycle")
    category: str                     # Category name (e.g., "Functions")
    attributes: List[str]             # Attribute list for this category
    model: Optional[str] = None
    temperature: Optional[float] = 0.7
    keyword_count: int = 3            # Number of new keywords to generate
    lang: LanguageType = "zh"         # Language for prompts


class TransformationDescription(BaseModel):
    """單一轉換描述"""
    keyword: str                      # 新關鍵字
    description: str                  # 與 query 結合的描述


class TransformationCategoryResult(BaseModel):
    """單一類別的轉換結果"""
    category: str
    original_attributes: List[str]    # 原始屬性
    new_keywords: List[str]           # 新生成的關鍵字
    descriptions: List[TransformationDescription]


class TransformationDAGResult(BaseModel):
    """完整 Transformation 結果"""
    query: str
    results: List[TransformationCategoryResult]


# ===== Expert Transformation Agent schemas =====

class ExpertProfile(BaseModel):
    """專家檔案"""
    id: str                           # e.g., "expert-0"
    name: str                         # e.g., "藥師"
    domain: str                       # e.g., "醫療與健康"
    perspective: Optional[str] = None # e.g., "從藥物與健康管理角度思考"


class ExpertKeyword(BaseModel):
    """專家視角生成的關鍵字"""
    keyword: str                      # 關鍵字本身
    expert_id: str                    # 哪個專家生成的
    expert_name: str                  # 專家名稱（冗餘，方便前端）
    source_attribute: str             # 來自哪個原始屬性


class ExpertTransformationDescription(BaseModel):
    """專家關鍵字的描述"""
    keyword: str
    expert_id: str
    expert_name: str
    description: str


class ExpertTransformationCategoryResult(BaseModel):
    """單一類別的轉換結果（專家版）"""
    category: str
    original_attributes: List[str]
    expert_keywords: List[ExpertKeyword]  # 所有專家生成的關鍵字
    descriptions: List[ExpertTransformationDescription]


class ExpertTransformationDAGResult(BaseModel):
    """完整轉換結果（專家版）"""
    query: str
    experts: List[ExpertProfile]      # 使用的專家列表
    results: List[ExpertTransformationCategoryResult]


class ExpertSource(str, Enum):
    """專家來源類型"""
    LLM = "llm"
    CURATED = "curated"  # 精選職業（210筆，含具體領域）
    DBPEDIA = "dbpedia"
    WIKIDATA = "wikidata"


class ExpertTransformationRequest(BaseModel):
    """Expert Transformation Agent request"""
    query: str
    category: str
    attributes: List[str]

    # Expert parameters
    expert_count: int = 3                        # Number of experts (2-8)
    keywords_per_expert: int = 1                 # Keywords per expert per attribute (1-3)
    custom_experts: Optional[List[str]] = None   # User-specified experts

    # Expert source parameters
    expert_source: ExpertSource = ExpertSource.LLM  # Expert source
    expert_language: str = "en"                     # Language for external sources

    # LLM parameters
    model: Optional[str] = None
    temperature: Optional[float] = 0.7

    # Prompt language
    lang: LanguageType = "zh"


# ===== Deduplication Agent schemas =====

class DeduplicationMethod(str, Enum):
    """去重方法"""
    EMBEDDING = "embedding"  # 向量相似度
    LLM = "llm"              # LLM 成對判斷


class DeduplicationRequest(BaseModel):
    """Deduplication request"""
    descriptions: List[ExpertTransformationDescription]
    method: DeduplicationMethod = DeduplicationMethod.EMBEDDING  # Deduplication method
    similarity_threshold: float = 0.85  # Cosine similarity threshold (0.0-1.0), only for Embedding
    model: Optional[str] = None  # Embedding/LLM model
    lang: LanguageType = "zh"  # Prompt language (for LLM method)


class DescriptionGroup(BaseModel):
    """相似描述分組"""
    group_id: str                          # "group-0", "group-1"...
    representative: ExpertTransformationDescription  # 代表描述
    duplicates: List[ExpertTransformationDescription]  # 相似描述
    similarity_scores: List[float]         # 每個重複項的相似度分數


class DeduplicationResult(BaseModel):
    """去重結果"""
    total_input: int           # 輸入描述總數
    total_groups: int          # 分組數量
    total_duplicates: int      # 重複項數量
    groups: List[DescriptionGroup]
    threshold_used: float
    method_used: DeduplicationMethod       # 使用的去重方法
    model_used: str                        # 使用的模型
