# -*- coding: utf-8 -*-
"""
管理端 — AI 监控后台 Pydantic Schema。

覆盖：Dashboard 总览、调度任务、调用记录、缓存失效、Token 预算、批量执行、告警管理。

需求: A1.1, A2.1, A4.1, A5.1, A6.1, A7.1, A8.1
"""

from __future__ import annotations

from pydantic import BaseModel


# ── Dashboard ─────────────────────────────────────────────


class DailyTrend(BaseModel):
    """近 7 天按日聚合趋势项。"""
    date: str                           # YYYY-MM-DD
    calls: int
    success_rate: float


class AppDistItem(BaseModel):
    """各 App 调用占比分布项。"""
    app_type: str
    count: int
    percentage: float


class BudgetInfo(BaseModel):
    """日/月 Token 预算进度。"""
    daily_used: int
    daily_limit: int
    daily_pct: float
    monthly_used: int
    monthly_limit: int
    monthly_pct: float


class AlertItem(BaseModel):
    """告警事件项（失败/超时/熔断）。"""
    id: int
    app_type: str
    status: str                         # failed / timeout / circuit_open
    alert_status: str | None            # pending / acknowledged / ignored
    error_message: str | None
    created_at: str


class AppHealthItem(BaseModel):
    """各 App 最近一次调用状态。"""
    app_type: str
    last_status: str | None
    last_call_at: str | None


class DashboardResponse(BaseModel):
    """Dashboard 总览统计响应。"""
    today_calls: int
    today_success_rate: float           # 0.0 ~ 1.0
    today_tokens: int
    today_avg_latency_ms: float
    trend_7d: list[DailyTrend]
    app_distribution: list[AppDistItem]
    budget: BudgetInfo
    recent_alerts: list[AlertItem]
    app_health: list[AppHealthItem]


# ── 调度任务 ──────────────────────────────────────────────


class TriggerJobItem(BaseModel):
    """调度任务列表项。"""
    id: int
    event_type: str
    member_id: int | None
    status: str
    app_chain: str | None
    is_forced: bool
    site_id: int
    started_at: str | None
    finished_at: str | None
    created_at: str


class TriggerJobListResponse(BaseModel):
    """调度任务分页列表响应。"""
    items: list[TriggerJobItem]
    total: int
    page: int
    page_size: int
    today_skipped_duplicates: int       # 今日去重跳过数


class TriggerJobDetailResponse(TriggerJobItem):
    """调度任务详情响应（含 payload、error_message）。"""
    payload: dict | None
    error_message: str | None
    connector_type: str


class RetryResponse(BaseModel):
    """手动重跑响应。"""
    trigger_job_id: int
    status: str                         # "pending"


# ── 调用记录 ──────────────────────────────────────────────


class RunLogItem(BaseModel):
    """调用记录列表项。"""
    id: int
    app_type: str
    trigger_type: str
    member_id: int | None
    tokens_used: int
    latency_ms: int | None
    status: str
    site_id: int
    created_at: str


class RunLogListResponse(BaseModel):
    """调用记录分页列表响应。"""
    items: list[RunLogItem]
    total: int
    page: int
    page_size: int


class RunLogDetailResponse(RunLogItem):
    """调用记录详情响应（含完整 prompt/response，不脱敏）。"""
    request_prompt: str | None
    response_text: str | None
    error_message: str | None
    session_id: str | None
    finished_at: str | None


# ── 缓存失效 ─────────────────────────────────────────────


class CacheInvalidateRequest(BaseModel):
    """缓存失效请求（site_id 必填）。"""
    site_id: int
    app_type: str | None = None
    member_id: int | None = None


class CacheInvalidateResponse(BaseModel):
    """缓存失效响应。"""
    affected_count: int


# ── Token 预算 ────────────────────────────────────────────


class BudgetResponse(BaseModel):
    """Token 预算使用情况响应。"""
    daily_used: int
    daily_limit: int
    daily_pct: float
    monthly_used: int
    monthly_limit: int
    monthly_pct: float


# ── 批量执行 ──────────────────────────────────────────────


class BatchRunRequest(BaseModel):
    """批量执行请求。"""
    app_types: list[str]
    member_ids: list[int]
    site_id: int


class BatchRunEstimate(BaseModel):
    """批量执行预估响应（不立即执行）。"""
    batch_id: str
    estimated_calls: int
    estimated_tokens: int


class BatchRunConfirm(BaseModel):
    """批量执行确认请求。"""
    batch_id: str


class BatchRunConfirmResponse(BaseModel):
    """批量执行确认响应。"""
    status: str                         # "started"


# ── 按需单 App 执行（/run/{app_type}）──────────────────────


class RunAppRequest(BaseModel):
    """按需执行单个 App 请求体。

    context 字段根据 app_type 不同有不同约束：
    - app2_finance: site_id + time_dimension + area（area 默认 all）
    - app3_clue / app7_customer: site_id + member_id
    - app4_analysis / app5_tactics: site_id + member_id + assistant_id
    - app6_note: site_id + member_id + note_content + noted_by_name
    - app8_consolidation: site_id + member_id
    """
    site_id: int
    member_id: int | None = None
    assistant_id: int | None = None
    time_dimension: str | None = None
    area: str | None = None             # App2 专用，默认 all
    note_content: str | None = None
    noted_by_name: str | None = None
    noted_by_created_at: str | None = None


class RunAppResponse(BaseModel):
    """按需执行单个 App 响应。"""
    app_type: str
    success: bool
    result: dict | None = None          # 百炼返回的 JSON（成功时）
    error: str | None = None            # 错误描述（失败时）


# ── 告警 ──────────────────────────────────────────────────


class AlertListResponse(BaseModel):
    """告警分页列表响应。"""
    items: list[AlertItem]
    total: int
    page: int
    page_size: int


class AlertActionResponse(BaseModel):
    """告警操作（确认/忽略）响应。"""
    id: int
    alert_status: str


# ── 触发器管理（biz.trigger_jobs）─────────────────────────


class TriggerItem(BaseModel):
    """触发器单条记录。"""
    id: int
    job_name: str
    job_type: str
    trigger_condition: str              # event / cron / interval
    trigger_config: dict                # {"event_name": ...} 或 {"cron_expression": ...}
    status: str                         # enabled / disabled
    description: str | None = None
    last_run_at: str | None = None
    next_run_at: str | None = None
    last_error: str | None = None


class TriggerUpdateRequest(BaseModel):
    """触发器更新请求（3 个字段至少填一个）。"""
    status: str | None = None           # enabled / disabled
    cron_expression: str | None = None  # 标准 5 段 cron
    description: str | None = None


# ── 预热进度（app2_finance 72 组合）───────────────────────


class PrewarmMissingItem(BaseModel):
    """缺失的预热组合项。"""
    target_id: str                      # this_month__all
    time_dimension: str
    area: str


class PrewarmProgressResponse(BaseModel):
    """app2_finance 预热进度响应。"""
    total: int                          # 固定 72
    done: int
    missing: list[PrewarmMissingItem]
    last_updated: str | None = None


# ── 手动事件触发（越过去重）───────────────────────────────


class ManualTriggerRequest(BaseModel):
    """手动触发 AI 事件请求。"""
    event_type: str                     # consumption / dws_completed / note_created / task_assigned
    site_id: int
    member_id: int | None = None
    assistant_id: int | None = None
    payload: dict | None = None
    is_forced: bool = True              # 默认跳过去重


class ManualTriggerResponse(BaseModel):
    """手动事件触发响应。"""
    trigger_job_id: int
    status: str = "pending"
