#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
表单数据操作 — 细粒度异常体系

异常层次：
    FormDataException                       (所有表单数据异常的基类)
    ├── FormNotFoundException               (表单不存在)
    ├── RecordNotFoundException             (记录不存在)
    ├── FormDataValidationError             (数据校验失败的基类)
    │   ├── UniqueConstraintError           (唯一约束冲突)
    │   ├── NotNullConstraintError          (非空约束违反)
    │   ├── CheckConstraintError            (CHECK 约束违反)
    │   ├── ForeignKeyConstraintError       (外键约束违反)
    │   ├── DataTypeMismatchError           (数据类型不匹配)
    │   └── DataTooLongError               (数据超长)
    ├── FormDataSchemaError                 (表结构/配置错误的基类)
    │   ├── TableNotFoundError              (表不存在)
    │   └── ColumnNotFoundError             (列不存在)
    ├── FormDataConnectionError             (连接相关错误的基类)
    │   ├── DatabaseConnectionError         (连接失败/断开)
    │   ├── ConnectionPoolExhaustedError    (连接池耗尽)
    │   └── ConnectionTimeoutError          (连接超时)
    ├── FormDataConcurrencyError            (并发相关错误的基类)
    │   ├── DeadlockError                   (死锁)
    │   └── LockTimeoutError               (锁等待超时)
    ├── QueryError                          (SQL 查询构建/执行错误)
    └── InternalDatabaseError               (其他数据库内部错误)

每个异常类携带 error_code 和结构化的上下文信息 (context)，
方便 API 层映射到 HTTP 响应 + 前端根据 error_code 做差异化处理。
"""
from __future__ import annotations

from typing import Any, Dict, Optional


# =====================================================================
#  基类
# =====================================================================

class FormDataException(Exception):
    """表单数据操作异常基类"""

    error_code: str = "FORM_DATA_ERROR"
    http_status: int = 400

    def __init__(
        self,
        message: str,
        *,
        error_code: Optional[str] = None,
        http_status: Optional[int] = None,
        context: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message)
        if error_code is not None:
            self.error_code = error_code
        if http_status is not None:
            self.http_status = http_status
        self.context: Dict[str, Any] = context or {}


# =====================================================================
#  资源不存在
# =====================================================================

class FormNotFoundException(FormDataException):
    """表单定义不存在"""
    error_code = "FORM_NOT_FOUND"
    http_status = 404

    def __init__(self, form_code: str):
        super().__init__(
            f"表单不存在: {form_code}",
            context={"form_code": form_code},
        )


class RecordNotFoundException(FormDataException):
    """记录不存在"""
    error_code = "RECORD_NOT_FOUND"
    http_status = 404

    def __init__(self, pk: Any, *, table: str = ""):
        super().__init__(
            f"数据不存在: {pk}",
            context={"pk": str(pk), "table": table},
        )


# =====================================================================
#  数据校验 / 约束违反
# =====================================================================

class FormDataValidationError(FormDataException):
    """数据校验失败的基类"""
    error_code = "VALIDATION_ERROR"
    http_status = 400


class UniqueConstraintError(FormDataValidationError):
    """唯一约束冲突（含重复数据信息）"""
    error_code = "UNIQUE_CONSTRAINT_VIOLATION"

    def __init__(
        self,
        message: str = "数据重复，违反唯一约束",
        *,
        fields: Optional[list[str]] = None,
        constraint_name: str = "",
    ):
        super().__init__(
            message,
            context={"fields": fields or [], "constraint_name": constraint_name},
        )


class NotNullConstraintError(FormDataValidationError):
    """非空约束违反"""
    error_code = "NOT_NULL_VIOLATION"

    def __init__(self, column: str = ""):
        msg = f"字段 '{column}' 不能为空" if column else "存在必填字段为空"
        super().__init__(msg, context={"column": column})


class CheckConstraintError(FormDataValidationError):
    """CHECK 约束违反"""
    error_code = "CHECK_CONSTRAINT_VIOLATION"

    def __init__(self, constraint_name: str = "", detail: str = ""):
        msg = "数据不满足校验规则"
        if constraint_name:
            msg += f" ({constraint_name})"
        super().__init__(msg, context={"constraint_name": constraint_name, "detail": detail})


class ForeignKeyConstraintError(FormDataValidationError):
    """外键约束违反（删除/更新时关联数据存在）"""
    error_code = "FOREIGN_KEY_VIOLATION"

    def __init__(
        self,
        message: str = "",
        *,
        detail: str = "",
        referenced_table: str = "",
        constraint_name: str = "",
    ):
        if not message:
            message = "操作失败，该数据被其他数据引用"
            if referenced_table:
                message = (
                    f"无法删除，该数据已被「{referenced_table}」引用，"
                    "请先删除或解除关联数据"
                )
            elif detail:
                message += f"（{detail}）"
        super().__init__(
            message,
            context={
                "detail": detail,
                "referenced_table": referenced_table,
                "constraint_name": constraint_name,
            },
        )


class DataTypeMismatchError(FormDataValidationError):
    """数据类型不匹配"""
    error_code = "DATA_TYPE_MISMATCH"

    def __init__(self, detail: str = ""):
        msg = "数据类型不匹配，请检查输入数据格式"
        if detail:
            msg += f"（{detail}）"
        super().__init__(msg, context={"detail": detail})


class DataTooLongError(FormDataValidationError):
    """数据长度超出字段限制"""
    error_code = "DATA_TOO_LONG"

    def __init__(self, column: str = "", max_length: int = 0):
        msg = f"字段 '{column}' 的数据过长" if column else "数据长度超出限制"
        if max_length:
            msg += f"（最大 {max_length} 个字符）"
        super().__init__(
            msg,
            context={"column": column, "max_length": max_length},
        )


# =====================================================================
#  表结构 / 配置错误
# =====================================================================

class FormDataSchemaError(FormDataException):
    """表结构或配置相关错误基类"""
    error_code = "SCHEMA_ERROR"
    http_status = 400


class TableNotFoundError(FormDataSchemaError):
    """数据库表不存在"""
    error_code = "TABLE_NOT_FOUND"

    def __init__(self, table: str = ""):
        msg = f"数据库表 {table} 不存在，请检查数据源配置" if table else "数据库表不存在"
        super().__init__(msg, context={"table": table})


class ColumnNotFoundError(FormDataSchemaError):
    """数据库列不存在"""
    error_code = "COLUMN_NOT_FOUND"

    def __init__(self, column: str = "", table: str = ""):
        msg = f"数据库字段 '{column}' 不存在" if column else "数据库字段不存在"
        msg += "，请检查表单配置与数据库表结构是否一致"
        super().__init__(msg, context={"column": column, "table": table})


# =====================================================================
#  连接相关
# =====================================================================

class FormDataConnectionError(FormDataException):
    """数据库连接相关错误基类"""
    error_code = "CONNECTION_ERROR"
    http_status = 503


class DatabaseConnectionError(FormDataConnectionError):
    """数据库连接失败或断开"""
    error_code = "DB_CONNECTION_FAILED"

    def __init__(self, detail: str = ""):
        msg = "数据库连接异常，请稍后重试"
        super().__init__(msg, context={"detail": detail})


class ConnectionPoolExhaustedError(FormDataConnectionError):
    """连接池耗尽"""
    error_code = "CONNECTION_POOL_EXHAUSTED"

    def __init__(self):
        super().__init__(
            "服务器繁忙（数据库连接池已满），请稍后重试",
        )


class ConnectionTimeoutError(FormDataConnectionError):
    """连接超时"""
    error_code = "CONNECTION_TIMEOUT"

    def __init__(self):
        super().__init__("数据库连接超时，请稍后重试")


# =====================================================================
#  并发相关
# =====================================================================

class FormDataConcurrencyError(FormDataException):
    """并发相关错误基类"""
    error_code = "CONCURRENCY_ERROR"
    http_status = 409


class DeadlockError(FormDataConcurrencyError):
    """死锁"""
    error_code = "DEADLOCK"

    def __init__(self):
        super().__init__("操作冲突（死锁），请重试")


class LockTimeoutError(FormDataConcurrencyError):
    """锁等待超时"""
    error_code = "LOCK_TIMEOUT"

    def __init__(self):
        super().__init__("操作等待超时，请稍后重试")


# =====================================================================
#  查询 / 其他
# =====================================================================

class QueryError(FormDataException):
    """SQL 查询构建或执行错误"""
    error_code = "QUERY_ERROR"
    http_status = 400

    def __init__(self, detail: str = ""):
        msg = "数据库查询异常，请检查表单配置是否正确"
        super().__init__(msg, context={"detail": detail})


class InternalDatabaseError(FormDataException):
    """其他未分类的数据库内部错误"""
    error_code = "INTERNAL_DB_ERROR"
    http_status = 500

    def __init__(self, detail: str = ""):
        msg = "数据库操作失败，请联系管理员"
        super().__init__(msg, context={"detail": detail})
