"""助教数据获取模块（应用 4/5 共用）。

从 ETL 库 app.v_* RLS 视图获取助教基本信息和助教-客户服务历史。
使用 is_delete 字段排除废单（is_delete=0 为正常），禁止使用已废弃的 dwd_assistant_trash_event 表。
"""
# CHANGE 2026-03-23 | Prompt: FDW 迁移——fdw_etl.* → app.* 直连 ETL 库
# intent: 将所有 fdw_etl.* 外部表引用改为 app.v_* RLS 视图（直连 ETL 库），列名同步修正
# 连接方式不变（get_etl_readonly_connection），仅改 SQL 表名和列名

from __future__ import annotations

import asyncio
import logging
from datetime import date, datetime
from decimal import Decimal
from functools import partial
from typing import Any

from app.database import get_etl_readonly_connection

logger = logging.getLogger(__name__)

FDW_QUERY_TIMEOUT_SEC = 5


async def fetch_assistant_info(
    site_id: int,
    assistant_id: int,
) -> dict[str, Any]:
    """获取助教基本信息。

    返回:
        {
            "nickname": str,
            "level": str,
            "hire_date": str,
            "tenure_months": int,
            "monthly_customers": int,
            "performance_tier": str,
        }

    Raises:
        ValueError: 助教不存在
        TimeoutError: FDW 查询超时
        ConnectionError: FDW 连接失败
    """
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        None,
        partial(_fetch_assistant_info_sync, site_id, assistant_id),
    )


def _fetch_assistant_info_sync(site_id: int, assistant_id: int) -> dict[str, Any]:
    """同步实现。"""
    conn = None
    try:
        conn = get_etl_readonly_connection(site_id)
        # RLS 隔离 + 语句超时（get_etl_readonly_connection 的 SET LOCAL 在 commit 后失效，
        # 需在查询事务中重新设置）
        # CHANGE 2026-05-02 | 同时下发 app.current_business_date，供 RLS 视图业务日上界裁剪
        from app.services.runtime_context import as_runtime_today_param as _rt_today
        _ref_date = _rt_today(site_id)
        with conn.cursor() as cur:
            cur.execute(
                "SET LOCAL app.current_site_id = %s", (str(site_id),)
            )
            cur.execute(
                "SET LOCAL app.current_business_date = %s", (_ref_date.isoformat(),)
            )
            cur.execute(
                "SET LOCAL statement_timeout = %s",
                (f"{FDW_QUERY_TIMEOUT_SEC * 1000}",),
            )

            # 基本信息
            # ⚠️ v_dim_assistant 列名: hire_date→entry_time
            cur.execute(
                """
                SELECT nickname, level, entry_time AS hire_date
                FROM app.v_dim_assistant
                WHERE assistant_id = %s AND scd2_is_current = 1
                LIMIT 1
                """,
                (assistant_id,),
            )
            row = cur.fetchone()
            if not row:
                raise ValueError(f"assistant not found: assistant_id={assistant_id}")

            nickname = row[0] or ""
            level = row[1] or ""
            hire_date = row[2]

            # 计算工龄（CHANGE 2026-05-02 | 用 business_date 替代 today，沙箱按当时工龄）
            from app.services.runtime_context import as_runtime_today_param
            ref_date = as_runtime_today_param(site_id)
            tenure_months = 0
            if hire_date and isinstance(hire_date, date):
                tenure_months = (ref_date.year - hire_date.year) * 12 + (ref_date.month - hire_date.month)

            # 绩效数据
            # ⚠️ 列名映射: monthly_customers 不存在（用 0 占位），performance_tier→tier_name
            # ⚠️ salary_month 是 date 类型（YYYY-MM-01），按月降序取最新
            cur.execute(
                """
                SELECT
                    0 AS monthly_customers,
                    COALESCE(tier_name, '') AS performance_tier
                FROM app.v_dws_assistant_salary_calc
                WHERE assistant_id = %s
                ORDER BY salary_month DESC
                LIMIT 1
                """,
                (assistant_id,),
            )
            perf_row = cur.fetchone()
            monthly_customers = perf_row[0] if perf_row else 0
            performance_tier = perf_row[1] if perf_row else ""

        conn.commit()
        return {
            "nickname": nickname,
            "level": level,
            "hire_date": hire_date.isoformat() if isinstance(hire_date, date) else "",
            "tenure_months": tenure_months,
            "monthly_customers": monthly_customers,
            "performance_tier": performance_tier,
        }

    except (ValueError, TimeoutError, ConnectionError):
        raise
    except Exception as e:
        err_msg = str(e).lower()
        if "statement timeout" in err_msg or "timeout" in err_msg:
            raise TimeoutError(
                f"FDW 查询超时: assistant_id={assistant_id}"
            ) from e
        if "connection" in err_msg or "connect" in err_msg:
            raise ConnectionError(
                f"FDW 连接失败: assistant_id={assistant_id}"
            ) from e
        raise
    finally:
        if conn:
            conn.close()


async def fetch_service_history(
    site_id: int,
    assistant_id: int,
    member_id: int,
    months: int = 3,
) -> list[dict[str, Any]]:
    """获取助教服务该客户的历史记录。

    使用 is_delete 排除废单（WHERE is_delete = 0）。

    返回:
        [
            {
                "service_date": str,
                "duration_minutes": int,
                "items_sum": float,
                "room_name": str,
                "is_pd": bool,
            },
            ...
        ]

    Raises:
        TimeoutError: FDW 查询超时
        ConnectionError: FDW 连接失败
    """
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        None,
        partial(_fetch_service_history_sync, site_id, assistant_id, member_id, months),
    )


def _fetch_service_history_sync(
    site_id: int,
    assistant_id: int,
    member_id: int,
    months: int,
) -> list[dict[str, Any]]:
    """同步实现。"""
    conn = None
    try:
        conn = get_etl_readonly_connection(site_id)
        # RLS 隔离 + 语句超时（get_etl_readonly_connection 的 SET LOCAL 在 commit 后失效，
        # 需在查询事务中重新设置）
        # CHANGE 2026-05-02 | 同时下发 app.current_business_date，供 RLS 视图业务日上界裁剪
        from app.services.runtime_context import as_runtime_today_param as _rt_today2
        _ref_date_outer = _rt_today2(site_id)
        with conn.cursor() as cur:
            cur.execute(
                "SET LOCAL app.current_site_id = %s", (str(site_id),)
            )
            cur.execute(
                "SET LOCAL app.current_business_date = %s", (_ref_date_outer.isoformat(),)
            )
            cur.execute(
                "SET LOCAL statement_timeout = %s",
                (f"{FDW_QUERY_TIMEOUT_SEC * 1000}",),
            )

            # ⚠️ 列名映射: assistant_id→site_assistant_id, member_id→tenant_member_id,
            # is_trash=false→is_delete=0, service_date→create_time,
            # duration_minutes→real_use_seconds/60, items_sum→ledger_amount,
            # room_name→site_table_id, is_pd→(order_assistant_type=1)
            # CHANGE 2026-05-02 | 用 business_date 替代 CURRENT_DATE，沙箱不读「未来」服务记录
            from app.services.runtime_context import as_runtime_today_param
            ref_date = as_runtime_today_param(site_id)
            cur.execute(
                """
                SELECT
                    create_time AS service_date,
                    COALESCE(real_use_seconds / 60, 0) AS duration_minutes,
                    ledger_amount AS items_sum,
                    site_table_id AS room_name,
                    (order_assistant_type = 1) AS is_pd
                FROM app.v_dwd_assistant_service_log
                WHERE site_assistant_id = %s
                  AND tenant_member_id = %s
                  AND is_delete = 0
                  AND create_time >= (%s::date - (INTERVAL '1 month' * %s))
                  AND create_time <  (%s::date + INTERVAL '1 day')
                ORDER BY create_time DESC
                """,
                (assistant_id, member_id, ref_date, months, ref_date),
            )
            columns = [desc[0] for desc in cur.description]
            rows = cur.fetchall()

        conn.commit()

        records = []
        for row in rows:
            record = {}
            for col, val in zip(columns, row):
                if isinstance(val, (date, datetime)):
                    record[col] = val.isoformat()
                elif isinstance(val, Decimal):
                    record[col] = float(val)
                elif isinstance(val, bool):
                    record[col] = val
                else:
                    record[col] = val
            records.append(record)

        return records

    except (TimeoutError, ConnectionError):
        raise
    except Exception as e:
        err_msg = str(e).lower()
        if "statement timeout" in err_msg or "timeout" in err_msg:
            raise TimeoutError(
                f"FDW 查询超时: assistant_id={assistant_id}, member_id={member_id}"
            ) from e
        if "connection" in err_msg or "connect" in err_msg:
            raise ConnectionError(
                f"FDW 连接失败: assistant_id={assistant_id}, member_id={member_id}"
            ) from e
        raise
    finally:
        if conn:
            conn.close()
