# -*- coding: utf-8 -*-
"""
申请服务 —— 处理用户申请的创建、查询、审核。

职责：
- create_application()：创建申请 + site_code 映射查找
- approve_application()：批准 + 创建绑定/角色
- reject_application()：拒绝 + 记录原因
- get_user_applications()：查询用户申请列表

所有数据库操作使用 psycopg2 原生 SQL，不引入 ORM。
"""

from __future__ import annotations

import logging

from fastapi import HTTPException, status

from app.database import get_connection
from app.trace.decorators import trace_service

logger = logging.getLogger(__name__)


@trace_service(description_zh="创建入驻申请", description_en="Create application")
async def create_application(
    user_id: int,
    site_code: str,
    applied_role_text: str,
    phone: str,
    employee_number: str | None = None,
    nickname: str | None = None,
) -> dict:
    """
    创建用户申请。

    1. 检查是否有 pending 申请（有则 409）
    2. 查找 site_code → site_id 映射
    3. 插入 user_applications 记录
    4. 更新 users.nickname（如提供）

    返回:
        申请记录 dict，包含 id / site_code / applied_role_text / status /
        review_note / created_at / reviewed_at
    """
    conn = get_connection()
    try:
        with conn.cursor() as cur:
            # 1. 检查重复 pending 申请
            cur.execute(
                """
                SELECT id FROM auth.user_applications
                 WHERE user_id = %s AND status = 'pending'
                 LIMIT 1
                """,
                (user_id,),
            )
            if cur.fetchone() is not None:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="已有待审核的申请，请等待审核完成",
                )

            # 2. 查找 site_code → site_id 映射（优先当前活跃编码，再查历史编码）
            # CHANGE 2026-03-23 | 大小写不敏感匹配 site_code（UPPER）
            site_id = None
            site_code_upper = site_code.upper()
            cur.execute(
                """
                SELECT site_id FROM biz.sites
                 WHERE UPPER(site_code) = %s AND is_active = true
                UNION ALL
                SELECT s.site_id FROM biz.site_code_history h
                  JOIN biz.sites s ON s.site_id = h.site_id
                 WHERE UPPER(h.site_code) = %s AND h.is_current = false AND s.is_active = true
                 LIMIT 1
                """,
                (site_code_upper, site_code_upper),
            )
            mapping_row = cur.fetchone()
            if mapping_row is not None:
                site_id = mapping_row[0]

            # 3. 创建申请记录
            cur.execute(
                """
                INSERT INTO auth.user_applications
                    (user_id, site_code, site_id, applied_role_text,
                     phone, employee_number, status)
                VALUES (%s, %s, %s, %s, %s, %s, 'pending')
                RETURNING id, site_code, applied_role_text, status,
                          review_note, created_at::text, reviewed_at::text
                """,
                (
                    user_id,
                    site_code,
                    site_id,
                    applied_role_text,
                    phone,
                    employee_number,
                ),
            )
            row = cur.fetchone()

            # 4. 更新 nickname（如提供）
            if nickname:
                cur.execute(
                    "UPDATE auth.users SET nickname = %s, updated_at = NOW() WHERE id = %s",
                    (nickname, user_id),
                )

            # 5. 更新用户状态为 pending（new → pending）
            cur.execute(
                """
                UPDATE auth.users SET status = 'pending', updated_at = NOW()
                 WHERE id = %s AND status IN ('new', 'rejected')
                """,
                (user_id,),
            )

            conn.commit()
    finally:
        conn.close()

    return {
        "id": row[0],
        "site_code": row[1],
        "applied_role_text": row[2],
        "status": row[3],
        "review_note": row[4],
        "created_at": row[5],
        "reviewed_at": row[6],
    }



@trace_service(description_zh="审批通过申请", description_en="Approve application")
async def approve_application(
    application_id: int,
    reviewer_id: int,
    role_id: int,
    binding: dict | None = None,
    review_note: str | None = None,
) -> dict:
    """
    批准申请。

    1. 查询申请记录（不存在则 404）
    2. 检查申请状态为 pending（否则 409）
    3. 更新 user_applications.status = 'approved'
    4. 创建 user_site_roles 记录
    5. 创建 user_assistant_binding 记录（如有 binding）
    6. 更新 users.status = 'approved'
    7. 记录 reviewer_id 和 reviewed_at

    参数:
        application_id: 申请 ID
        reviewer_id: 审核人 user_id
        role_id: 分配的角色 ID
        binding: 绑定信息，格式 {"assistant_id": ..., "staff_id": ..., "binding_type": ...}
        review_note: 审核备注（可选）

    返回:
        更新后的申请记录 dict
    """
    conn = get_connection()
    try:
        with conn.cursor() as cur:
            # 1. 查询申请记录
            cur.execute(
                """
                SELECT id, user_id, site_id, status
                  FROM auth.user_applications
                 WHERE id = %s
                """,
                (application_id,),
            )
            app_row = cur.fetchone()
            if app_row is None:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="申请不存在",
                )

            _, app_user_id, app_site_id, app_status = app_row

            # 2. 检查状态为 pending
            if app_status != "pending":
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail=f"申请当前状态为 {app_status}，无法审核",
                )

            # 3. 更新申请状态为 approved
            cur.execute(
                """
                UPDATE auth.user_applications
                   SET status = 'approved',
                       reviewer_id = %s,
                       review_note = %s,
                       reviewed_at = NOW()
                 WHERE id = %s
                RETURNING id, site_code, applied_role_text, status,
                          review_note, created_at::text, reviewed_at::text
                """,
                (reviewer_id, review_note, application_id),
            )
            updated_row = cur.fetchone()

            # 4. 创建 user_site_roles 记录（如果有 site_id）
            if app_site_id is not None:
                cur.execute(
                    """
                    INSERT INTO auth.user_site_roles (user_id, site_id, role_id)
                    VALUES (%s, %s, %s)
                    ON CONFLICT (user_id, site_id, role_id) DO NOTHING
                    """,
                    (app_user_id, app_site_id, role_id),
                )

            # 5. 创建 user_assistant_binding 记录（如有 binding 且有 site_id）
            if binding and app_site_id is not None:
                cur.execute(
                    """
                    INSERT INTO auth.user_assistant_binding
                        (user_id, site_id, assistant_id, staff_id, binding_type)
                    VALUES (%s, %s, %s, %s, %s)
                    """,
                    (
                        app_user_id,
                        app_site_id,
                        binding.get("assistant_id"),
                        binding.get("staff_id"),
                        binding.get("binding_type", "assistant"),
                    ),
                )

            # 6. 更新用户状态为 approved
            cur.execute(
                """
                UPDATE auth.users
                   SET status = 'approved', updated_at = NOW()
                 WHERE id = %s
                """,
                (app_user_id,),
            )

            conn.commit()
    finally:
        conn.close()

    return {
        "id": updated_row[0],
        "site_code": updated_row[1],
        "applied_role_text": updated_row[2],
        "status": updated_row[3],
        "review_note": updated_row[4],
        "created_at": updated_row[5],
        "reviewed_at": updated_row[6],
    }


@trace_service(description_zh="驳回申请", description_en="Reject application")
async def reject_application(
    application_id: int,
    reviewer_id: int,
    review_note: str,
) -> dict:
    """
    拒绝申请。

    1. 查询申请记录（不存在则 404）
    2. 检查申请状态为 pending（否则 409）
    3. 更新 user_applications.status = 'rejected'
    4. 记录 reviewer_id、review_note、reviewed_at
    5. 累加 users.rejection_count，达到 3 次自动禁用

    返回:
        更新后的申请记录 dict（含 user_disabled 标记）
    """
    conn = get_connection()
    user_disabled = False
    try:
        with conn.cursor() as cur:
            # 1. 查询申请记录（含 user_id）
            cur.execute(
                "SELECT id, user_id, status FROM auth.user_applications WHERE id = %s",
                (application_id,),
            )
            app_row = cur.fetchone()
            if app_row is None:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="申请不存在",
                )

            _, app_user_id, app_status = app_row

            # 2. 检查状态为 pending
            if app_status != "pending":
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail=f"申请当前状态为 {app_status}，无法审核",
                )

            # 3. 更新申请状态为 rejected
            cur.execute(
                """
                UPDATE auth.user_applications
                   SET status = 'rejected',
                       reviewer_id = %s,
                       review_note = %s,
                       reviewed_at = NOW()
                 WHERE id = %s
                RETURNING id, site_code, applied_role_text, status,
                          review_note, created_at::text, reviewed_at::text
                """,
                (reviewer_id, review_note, application_id),
            )
            updated_row = cur.fetchone()

            # 4. 累加 rejection_count 并检查是否达到禁用阈值
            cur.execute(
                """
                UPDATE auth.users
                   SET rejection_count = rejection_count + 1,
                       updated_at = NOW()
                 WHERE id = %s
                RETURNING rejection_count
                """,
                (app_user_id,),
            )
            new_count = cur.fetchone()[0]

            if new_count >= 3:
                # 第三次拒绝：自动禁用账号
                cur.execute(
                    """
                    UPDATE auth.users
                       SET status = 'disabled', updated_at = NOW()
                     WHERE id = %s
                    """,
                    (app_user_id,),
                )
                user_disabled = True
                logger.warning(
                    "用户 %s 累计被拒绝 %d 次，已自动禁用",
                    app_user_id, new_count,
                )
            else:
                # 未达阈值：回退用户状态为 rejected（允许重新申请）
                cur.execute(
                    """
                    UPDATE auth.users
                       SET status = 'rejected', updated_at = NOW()
                     WHERE id = %s
                    """,
                    (app_user_id,),
                )

            conn.commit()
    finally:
        conn.close()

    return {
        "id": updated_row[0],
        "site_code": updated_row[1],
        "applied_role_text": updated_row[2],
        "status": updated_row[3],
        "review_note": updated_row[4],
        "created_at": updated_row[5],
        "reviewed_at": updated_row[6],
        "user_disabled": user_disabled,
    }


@trace_service(description_zh="获取用户申请列表", description_en="Get user applications")
async def get_user_applications(user_id: int) -> list[dict]:
    """
    查询用户的所有申请记录。

    按创建时间倒序排列。

    返回:
        申请记录 dict 列表（含 phone、employee_number）
    """
    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(
                """
                SELECT id, site_code, applied_role_text, phone,
                       employee_number, status,
                       review_note, created_at::text, reviewed_at::text
                  FROM auth.user_applications
                 WHERE user_id = %s
                 ORDER BY created_at DESC
                """,
                (user_id,),
            )
            rows = cur.fetchall()
    finally:
        conn.close()

    return [
        {
            "id": r[0],
            "site_code": r[1],
            "applied_role_text": r[2],
            "phone": r[3],
            "employee_number": r[4],
            "status": r[5],
            "review_note": r[6],
            "created_at": r[7],
            "reviewed_at": r[8],
        }
        for r in rows
    ]


@trace_service(description_zh="取消申请", description_en="Cancel application")
async def cancel_application(user_id: int) -> dict:
    """
    用户主动取消当前 pending 申请。

    1. 查找用户的 pending 申请（无则 404）
    2. 更新申请 status = 'cancelled'
    3. 回退用户 status 为 'new'

    返回:
        被取消的申请记录 dict
    """
    conn = get_connection()
    try:
        with conn.cursor() as cur:
            # 1. 查找 pending 申请
            cur.execute(
                """
                SELECT id FROM auth.user_applications
                 WHERE user_id = %s AND status = 'pending'
                 ORDER BY created_at DESC
                 LIMIT 1
                """,
                (user_id,),
            )
            row = cur.fetchone()
            if row is None:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="没有待审核的申请",
                )

            application_id = row[0]

            # 2. 更新申请状态为 cancelled
            cur.execute(
                """
                UPDATE auth.user_applications
                   SET status = 'cancelled'
                 WHERE id = %s
                RETURNING id, site_code, applied_role_text, phone,
                          employee_number, status, created_at::text
                """,
                (application_id,),
            )
            updated_row = cur.fetchone()

            # 3. 回退用户状态为 new
            cur.execute(
                """
                UPDATE auth.users
                   SET status = 'new', updated_at = NOW()
                 WHERE id = %s
                """,
                (user_id,),
            )

            conn.commit()
    finally:
        conn.close()

    return {
        "id": updated_row[0],
        "site_code": updated_row[1],
        "applied_role_text": updated_row[2],
        "phone": updated_row[3],
        "employee_number": updated_row[4],
        "status": updated_row[5],
        "created_at": updated_row[6],
    }
