from datetime import datetime
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel


# ============ Enums ============
class AssistantConfigMode(str, Enum):
    PLATFORM = "platform"
    DIFY = "dify"
    FASTGPT = "fastgpt"
    NONE = "none"


class LLMModelType(str, Enum):
    TEXT = "text"
    EMBEDDING = "embedding"
    RERANK = "rerank"


class ASRLanguage(str, Enum):
    ZH = "zh"
    EN = "en"
    MULTILINGUAL = "Multi-lingual"


class VoiceGender(str, Enum):
    MALE = "Male"
    FEMALE = "Female"


class CallRecordSource(str, Enum):
    DEBUG = "debug"
    EXTERNAL = "external"


class CallRecordStatus(str, Enum):
    CONNECTED = "connected"
    MISSED = "missed"
    FAILED = "failed"


# ============ Voice ============
class VoiceBase(BaseModel):
    name: str
    vendor: str
    gender: str  # "Male" | "Female"
    language: str  # "zh" | "en"
    description: str = ""


class VoiceCreate(VoiceBase):
    id: Optional[str] = None
    model: Optional[str] = None  # 厂商语音模型标识
    voice_key: Optional[str] = None  # 厂商voice_key
    api_key: Optional[str] = None
    base_url: Optional[str] = None
    speed: float = 1.0
    gain: int = 0
    pitch: int = 0
    enabled: bool = True


class VoiceUpdate(BaseModel):
    name: Optional[str] = None
    vendor: Optional[str] = None
    gender: Optional[str] = None
    language: Optional[str] = None
    description: Optional[str] = None
    model: Optional[str] = None
    voice_key: Optional[str] = None
    api_key: Optional[str] = None
    base_url: Optional[str] = None
    speed: Optional[float] = None
    gain: Optional[int] = None
    pitch: Optional[int] = None
    enabled: Optional[bool] = None


class VoiceOut(VoiceBase):
    id: str
    user_id: Optional[int] = None
    model: Optional[str] = None
    voice_key: Optional[str] = None
    api_key: Optional[str] = None
    base_url: Optional[str] = None
    speed: float = 1.0
    gain: int = 0
    pitch: int = 0
    enabled: bool = True
    is_system: bool = False
    created_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class VoicePreviewRequest(BaseModel):
    text: str
    api_key: Optional[str] = None
    speed: Optional[float] = None
    gain: Optional[int] = None
    pitch: Optional[int] = None


class VoicePreviewResponse(BaseModel):
    success: bool
    audio_url: Optional[str] = None
    duration_ms: Optional[int] = None
    error: Optional[str] = None


# ============ LLM Model ============
class LLMModelBase(BaseModel):
    name: str
    vendor: str
    type: LLMModelType
    base_url: str
    api_key: str
    model_name: Optional[str] = None
    temperature: Optional[float] = None
    context_length: Optional[int] = None
    enabled: bool = True


class LLMModelCreate(LLMModelBase):
    id: Optional[str] = None


class LLMModelUpdate(BaseModel):
    name: Optional[str] = None
    vendor: Optional[str] = None
    type: Optional[LLMModelType] = None
    base_url: Optional[str] = None
    api_key: Optional[str] = None
    model_name: Optional[str] = None
    temperature: Optional[float] = None
    context_length: Optional[int] = None
    enabled: Optional[bool] = None


class LLMModelOut(LLMModelBase):
    id: str
    user_id: int
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class LLMModelTestResponse(BaseModel):
    success: bool
    latency_ms: Optional[int] = None
    message: Optional[str] = None


class LLMPreviewRequest(BaseModel):
    message: str
    system_prompt: Optional[str] = None
    max_tokens: Optional[int] = None
    temperature: Optional[float] = None
    api_key: Optional[str] = None


class LLMPreviewResponse(BaseModel):
    success: bool
    reply: Optional[str] = None
    usage: Optional[dict] = None
    latency_ms: Optional[int] = None
    error: Optional[str] = None


# ============ ASR Model ============
class ASRModelBase(BaseModel):
    name: str
    vendor: str
    language: str  # "zh" | "en" | "Multi-lingual"
    base_url: str
    api_key: str
    model_name: Optional[str] = None
    enabled: bool = True


class ASRModelCreate(ASRModelBase):
    id: Optional[str] = None
    hotwords: List[str] = []
    enable_punctuation: bool = True
    enable_normalization: bool = True


class ASRModelUpdate(BaseModel):
    name: Optional[str] = None
    language: Optional[str] = None
    base_url: Optional[str] = None
    api_key: Optional[str] = None
    model_name: Optional[str] = None
    hotwords: Optional[List[str]] = None
    enable_punctuation: Optional[bool] = None
    enable_normalization: Optional[bool] = None
    enabled: Optional[bool] = None


class ASRModelOut(ASRModelBase):
    id: str
    user_id: int
    hotwords: List[str] = []
    enable_punctuation: bool = True
    enable_normalization: bool = True
    created_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class ASRTestRequest(BaseModel):
    audio_url: Optional[str] = None
    audio_data: Optional[str] = None  # base64 encoded


class ASRTestResponse(BaseModel):
    success: bool
    transcript: Optional[str] = None
    language: Optional[str] = None
    confidence: Optional[float] = None
    duration_ms: Optional[int] = None
    latency_ms: Optional[int] = None
    message: Optional[str] = None
    error: Optional[str] = None


# ============ Tool Resource ============
class ToolResourceBase(BaseModel):
    name: str
    description: str = ""
    category: str = "system"  # system/query
    icon: str = "Wrench"
    enabled: bool = True


class ToolResourceCreate(ToolResourceBase):
    id: Optional[str] = None


class ToolResourceUpdate(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    category: Optional[str] = None
    icon: Optional[str] = None
    enabled: Optional[bool] = None


class ToolResourceOut(ToolResourceBase):
    id: str
    user_id: Optional[int] = None
    is_system: bool = False
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


# ============ Assistant ============
class AssistantBase(BaseModel):
    name: str
    opener: str = ""
    prompt: str = ""
    knowledgeBaseId: Optional[str] = None
    language: str = "zh"
    voice: Optional[str] = None
    speed: float = 1.0
    hotwords: List[str] = []
    tools: List[str] = []
    interruptionSensitivity: int = 500
    configMode: str = "platform"
    apiUrl: Optional[str] = None
    apiKey: Optional[str] = None
    # 模型关联
    llmModelId: Optional[str] = None
    asrModelId: Optional[str] = None
    embeddingModelId: Optional[str] = None
    rerankModelId: Optional[str] = None


class AssistantCreate(AssistantBase):
    pass


class AssistantUpdate(BaseModel):
    name: Optional[str] = None
    opener: Optional[str] = None
    prompt: Optional[str] = None
    knowledgeBaseId: Optional[str] = None
    language: Optional[str] = None
    voice: Optional[str] = None
    speed: Optional[float] = None
    hotwords: Optional[List[str]] = None
    tools: Optional[List[str]] = None
    interruptionSensitivity: Optional[int] = None
    configMode: Optional[str] = None
    apiUrl: Optional[str] = None
    apiKey: Optional[str] = None
    llmModelId: Optional[str] = None
    asrModelId: Optional[str] = None
    embeddingModelId: Optional[str] = None
    rerankModelId: Optional[str] = None


class AssistantOut(AssistantBase):
    id: str
    callCount: int = 0
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class AssistantStats(BaseModel):
    assistant_id: str
    total_calls: int = 0
    connected_calls: int = 0
    missed_calls: int = 0
    avg_duration_seconds: float = 0.0
    today_calls: int = 0


# ============ Knowledge Base ============
class KnowledgeDocument(BaseModel):
    id: str
    name: str
    size: str
    fileType: str = "txt"
    storageUrl: Optional[str] = None
    status: str = "pending"
    chunkCount: int = 0
    uploadDate: str


class KnowledgeDocumentCreate(BaseModel):
    name: str
    size: str
    fileType: str = "txt"
    storageUrl: Optional[str] = None


class KnowledgeDocumentUpdate(BaseModel):
    status: Optional[str] = None
    chunkCount: Optional[int] = None
    errorMessage: Optional[str] = None


class KnowledgeBaseBase(BaseModel):
    name: str
    description: str = ""
    embeddingModel: str = "text-embedding-3-small"
    chunkSize: int = 500
    chunkOverlap: int = 50


class KnowledgeBaseCreate(KnowledgeBaseBase):
    pass


class KnowledgeBaseUpdate(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    embeddingModel: Optional[str] = None
    chunkSize: Optional[int] = None
    chunkOverlap: Optional[int] = None
    status: Optional[str] = None


class KnowledgeBaseOut(KnowledgeBaseBase):
    id: str
    docCount: int = 0
    chunkCount: int = 0
    status: str = "active"
    createdAt: Optional[datetime] = None
    updatedAt: Optional[datetime] = None
    documents: List[KnowledgeDocument] = []

    class Config:
        from_attributes = True


# ============ Knowledge Search ============
class KnowledgeSearchQuery(BaseModel):
    query: str
    kb_id: str
    nResults: int = 5


class KnowledgeSearchResult(BaseModel):
    query: str
    results: List[dict]


class DocumentIndexRequest(BaseModel):
    document_id: str
    content: str


class KnowledgeStats(BaseModel):
    kb_id: str
    docCount: int
    chunkCount: int


# ============ Workflow ============
class WorkflowNode(BaseModel):
    name: str
    type: str
    isStart: Optional[bool] = None
    metadata: dict
    prompt: Optional[str] = None
    messagePlan: Optional[dict] = None
    variableExtractionPlan: Optional[dict] = None
    tool: Optional[dict] = None
    globalNodePlan: Optional[dict] = None


class WorkflowEdge(BaseModel):
    from_: str
    to: str
    label: Optional[str] = None

    class Config:
        populate_by_name = True


class WorkflowBase(BaseModel):
    name: str
    nodeCount: int = 0
    createdAt: str = ""
    updatedAt: str = ""
    globalPrompt: Optional[str] = None
    nodes: List[dict] = []
    edges: List[dict] = []


class WorkflowCreate(WorkflowBase):
    pass


class WorkflowUpdate(BaseModel):
    name: Optional[str] = None
    nodeCount: Optional[int] = None
    nodes: Optional[List[dict]] = None
    edges: Optional[List[dict]] = None
    globalPrompt: Optional[str] = None


class WorkflowOut(WorkflowBase):
    id: str

    class Config:
        from_attributes = True


# ============ Call Record ============
class TranscriptSegment(BaseModel):
    turnIndex: int
    speaker: str  # human/ai
    content: str
    confidence: Optional[float] = None
    startMs: int
    endMs: int
    durationMs: Optional[int] = None
    audioUrl: Optional[str] = None
    emotion: Optional[str] = None


class CallRecordCreate(BaseModel):
    user_id: int
    assistant_id: Optional[str] = None
    source: str = "debug"
    status: Optional[str] = None
    cost: Optional[float] = None


class CallRecordUpdate(BaseModel):
    status: Optional[str] = None
    summary: Optional[str] = None
    duration_seconds: Optional[int] = None
    ended_at: Optional[str] = None
    cost: Optional[float] = None
    metadata: Optional[dict] = None


class CallRecordOut(BaseModel):
    id: str
    user_id: int
    assistant_id: Optional[str] = None
    source: str
    status: str
    started_at: str
    ended_at: Optional[str] = None
    duration_seconds: Optional[int] = None
    summary: Optional[str] = None
    cost: float = 0.0
    metadata: dict = {}
    created_at: Optional[datetime] = None
    transcripts: List[TranscriptSegment] = []

    class Config:
        from_attributes = True


# ============ Call Transcript ============
class TranscriptCreate(BaseModel):
    turn_index: int
    speaker: str
    content: str
    confidence: Optional[float] = None
    start_ms: int
    end_ms: int
    duration_ms: Optional[int] = None
    emotion: Optional[str] = None


class TranscriptOut(TranscriptCreate):
    id: int
    audio_url: Optional[str] = None

    class Config:
        from_attributes = True


# ============ History Stats ============
class HistoryStats(BaseModel):
    total_calls: int = 0
    connected_calls: int = 0
    missed_calls: int = 0
    failed_calls: int = 0
    avg_duration_seconds: float = 0.0
    total_cost: float = 0.0
    by_status: dict = {}
    by_source: dict = {}
    daily_trend: List[dict] = []


# ============ Dashboard ============
class DashboardStats(BaseModel):
    totalCalls: int
    answerRate: int
    avgDuration: str
    humanTransferCount: int
    trend: List[dict]


# ============ API Response ============
class Message(BaseModel):
    message: str


class DocumentIndexRequest(BaseModel):
    content: str


class ListResponse(BaseModel):
    total: int
    page: int
    limit: int
    list: List


class SearchResult(BaseModel):
    id: str
    started_at: str
    matched_content: Optional[str] = None
