"""QModel 兼容层基类模块

提供 SQLAlchemy 风格的链式 OOP 查询接口，使 Django ORM 支持：

- ``Model.query.filter(...)`` — 链式 FluentQuery 查询
- ``Model.field_name`` — 类级别返回 FieldExpression（支持 ``==``, ``>``, ``in_()`` 等运算符）
- ``Model.field_name`` — 实例级别返回字段值（与原生 Django Model 一致）
- ``Model[condition]`` — 快捷 filter 语法

典型用法::

    # 链式查询
    orders = Dingdan.query.filter(zhuangtai=8).order_by('-CreateTime').to_list()

    # 字段表达式
    Dingdan.query.filter(Dingdan.jine > 100, Dingdan.zhuangtai.in_([1, 2, 3]))

    # 聚合
    Dingdan.query.aggregate(total=Sum('jine'))

    # 分页
    Dingdan.query.paginate(page=1, per_page=20)
"""
from __future__ import annotations

import re
from typing import Any, Callable, Dict, Generic, Optional, Tuple, Type, TypeVar, Union

try:
    from typing import Self
except ImportError:
    from typing_extensions import Self

from django.db import models
from django.db.models import Q

from .fluent import FluentQuery


# ---------------------------------------------------------------------------
# 工具函数
# ---------------------------------------------------------------------------

#: classproperty 返回值类型变量
_RT = TypeVar('_RT')

#: QModel 子类类型变量（仅用于 __class_getitem__ 兼容）
_QM = TypeVar('_QM', bound='QModel')


class classproperty(Generic[_RT]):
    """类属性描述符，支持 ``Model.query`` 等类级别属性访问。

    泛型参数 ``_RT`` 传播函数返回类型，使 Pylance 能穿透描述符推断
    ``Model.query`` 的返回类型为 ``FluentQuery[Self]``。
    """

    def __init__(self, func: Callable[[type], _RT]) -> None:
        self.fget = func

    def __get__(self, obj: Any, objtype: Optional[type] = None) -> _RT:
        return self.fget(objtype if objtype is not None else type(obj))


ABBREVIATIONS: Dict[str, str] = {
    'uuid': 'UUID', 'id': 'ID', 'ip': 'IP', 'url': 'URL', 'uri': 'URI',
    'api': 'API', 'html': 'HTML', 'css': 'CSS', 'js': 'JS', 'json': 'JSON',
    'xml': 'XML', 'sql': 'SQL', 'http': 'HTTP', 'https': 'HTTPS',
    'smtp': 'SMTP', 'ssl': 'SSL', 'tls': 'TLS', 'ssh': 'SSH', 'ftp': 'FTP',
    '2fa': '2FA', 'elt': 'ELT', 'sve': 'SVE', 't4': 'T4', 'mc': 'MC',
    'crb': 'CRB', 'ccgo': 'CCGO', 'ugm': 'UGM', 'gerp': 'GERP',
    'abac': 'ABAC', 'rbac': 'RBAC', 'smtm': 'SMTM', 'pwd': 'PWD',
}


def snake_to_pascal(name: str) -> str:
    """将 snake_case 转换为 PascalCase，自动识别常见缩写。

    >>> snake_to_pascal('user_uuid')
    'UserUUID'
    >>> snake_to_pascal('paifa_dingdan_shu')
    'PaifaDingdanShu'
    """
    if '_' not in name:
        return name[0].upper() + name[1:] if name else name
    parts = name.split('_')
    result = []
    for p in parts:
        lower = p.lower()
        if lower in ABBREVIATIONS:
            result.append(ABBREVIATIONS[lower])
        else:
            result.append(p.capitalize())
    return ''.join(result)


def pascal_to_snake(name: str) -> str:
    """将 PascalCase 转换为 snake_case。

    >>> pascal_to_snake('UserUUID')
    'user_uuid'
    """
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
    return s2.lower()


# ---------------------------------------------------------------------------
# 字段表达式（类级别访问 Model.field 时返回）
# ---------------------------------------------------------------------------

class _InvertedFieldExpression:
    """取反字段表达式，由 ``~Model.field`` 产生，支持 ``~field.startswith(...)`` 等否定查询。"""

    def __init__(self, field_expr: FieldExpression) -> None:
        self._field_expr = field_expr

    def startswith(self, value: str) -> Q:
        return ~Q(**{f'{self._field_expr._django_name}__startswith': value})

    def contains(self, value: str) -> Q:
        return ~Q(**{f'{self._field_expr._django_name}__contains': value})

    def like(self, pattern: str) -> Q:
        clean = pattern.strip('%')
        return ~Q(**{f'{self._field_expr._django_name}__icontains': clean})

    def in_(self, values) -> Q:
        return ~Q(**{f'{self._field_expr._django_name}__in': values})

    def is_(self, other) -> Q:
        if other is None:
            return ~Q(**{f'{self._field_expr._django_name}__isnull': True})
        return ~Q(**{self._field_expr._django_name: other})

    def between(self, low, high) -> Q:
        return ~(Q(**{f'{self._field_expr._django_name}__gte': low})
                 & Q(**{f'{self._field_expr._django_name}__lte': high}))

    def __repr__(self) -> str:
        return f'~{self._field_expr!r}'


class FieldExpression:
    """字段表达式，由类级别 ``Model.field_name`` 访问产生。

    支持通过 Python 运算符构建 Django Q 对象::

        Model.field == value      → Q(field=value)
        Model.field > value       → Q(field__gt=value)
        Model.field.in_([1,2,3])  → Q(field__in=[1,2,3])
        Model.field.between(a, b) → Q(field__gte=a) & Q(field__lte=b)
        ~Model.field              → _InvertedFieldExpression（否定查询）
    """

    _resolve_cache: Dict[Tuple[str, str], str] = {}

    def __init__(self, model_class: Type, field_name: str) -> None:
        self.model_class = model_class
        self.field_name = field_name
        self._django_name: str = self._resolve_django_name()

    def _resolve_django_name(self) -> str:
        """将 Python 字段名解析为 Django ORM 查询使用的字段名。"""
        cache_key = (self.model_class.__name__, self.field_name)
        if cache_key in FieldExpression._resolve_cache:
            return FieldExpression._resolve_cache[cache_key]
        if hasattr(self.model_class, '_meta'):
            for f in self.model_class._meta.local_fields:
                if f.name == self.field_name:
                    FieldExpression._resolve_cache[cache_key] = f.name
                    return f.name
        FieldExpression._resolve_cache[cache_key] = self.field_name
        return self.field_name

    # ---- 比较运算符 ----

    def __eq__(self, other) -> Q:  # type: ignore[override]
        if isinstance(other, FieldExpression):
            return NotImplemented
        if other is None:
            return Q(**{f'{self._django_name}__isnull': True})
        return Q(**{self._django_name: other})

    def __ne__(self, other) -> Q:  # type: ignore[override]
        if isinstance(other, FieldExpression):
            return NotImplemented
        return ~Q(**{self._django_name: other})

    def __gt__(self, other) -> Q:
        return Q(**{f'{self._django_name}__gt': other})

    def __ge__(self, other) -> Q:
        return Q(**{f'{self._django_name}__gte': other})

    def __lt__(self, other) -> Q:
        return Q(**{f'{self._django_name}__lt': other})

    def __le__(self, other) -> Q:
        return Q(**{f'{self._django_name}__lte': other})

    def __hash__(self) -> int:
        return hash((self.model_class.__name__, self.field_name))

    # ---- 逻辑运算符 ----

    def __and__(self, other) -> Q:
        if isinstance(other, Q):
            return Q(self) & other
        if isinstance(other, FieldExpression):
            return Q(self) & Q(other)
        return NotImplemented

    def __or__(self, other) -> Q:
        if isinstance(other, Q):
            return Q(self) | other
        if isinstance(other, FieldExpression):
            return Q(self) | Q(other)
        return NotImplemented

    def __invert__(self) -> _InvertedFieldExpression:
        return _InvertedFieldExpression(self)

    # ---- 查询方法 ----

    def is_(self, other) -> Q:
        """``field IS NULL`` 或 ``field IS value``。"""
        if other is None:
            return Q(**{f'{self._django_name}__isnull': True})
        return Q(**{self._django_name: other})

    def is_not(self, other) -> Q:
        """``field IS NOT NULL`` 或 ``field IS NOT value``。"""
        if other is None:
            return Q(**{f'{self._django_name}__isnull': False})
        return ~Q(**{self._django_name: other})

    def like(self, pattern: str) -> Q:
        """模糊匹配（不区分大小写），自动去除 ``%`` 通配符。"""
        clean = pattern.strip('%')
        return Q(**{f'{self._django_name}__icontains': clean})

    def contains(self, value: str) -> Q:
        """包含子串（区分大小写）。"""
        return Q(**{f'{self._django_name}__contains': value})

    def ilike(self, pattern: str) -> Q:
        """like() 的别名。"""
        return self.like(pattern)

    def startswith(self, value: str) -> Q:
        """前缀匹配（区分大小写）。"""
        return Q(**{f'{self._django_name}__startswith': value})

    def istartswith(self, value: str) -> Q:
        """前缀匹配（不区分大小写）。"""
        return Q(**{f'{self._django_name}__istartswith': value})

    def endswith(self, value: str) -> Q:
        """后缀匹配（区分大小写）。"""
        return Q(**{f'{self._django_name}__endswith': value})

    def iendswith(self, value: str) -> Q:
        """后缀匹配（不区分大小写）。"""
        return Q(**{f'{self._django_name}__iendswith': value})

    def in_(self, values) -> Q:
        """``field IN (values)``，支持列表和 FluentQuery 子查询。"""
        if hasattr(values, '_qs'):
            return Q(**{f'{self._django_name}__in': values._qs.values(self._django_name)})
        return Q(**{f'{self._django_name}__in': values})

    def between(self, low, high) -> Q:
        """``field BETWEEN low AND high``。"""
        return Q(**{f'{self._django_name}__gte': low}) & Q(**{f'{self._django_name}__lte': high})

    def regex(self, pattern: str) -> Q:
        """正则匹配（区分大小写）。"""
        return Q(**{f'{self._django_name}__regex': pattern})

    def iregex(self, pattern: str) -> Q:
        """正则匹配（不区分大小写）。"""
        return Q(**{f'{self._django_name}__iregex': pattern})

    # ---- 排序辅助 ----

    def desc(self) -> str:
        """返回降序排序字符串 ``'-field_name'``。"""
        return f'-{self._django_name}'

    def asc(self) -> str:
        """返回升序排序字符串 ``'field_name'``。"""
        return self._django_name

    # ---- JSON 字段访问 ----

    def __getitem__(self, key: str) -> _JsonKeyExpression:
        """访问 JSON 字段内的键，如 ``Model.meta['key'] == value``。"""
        return _JsonKeyExpression(self._django_name, key)

    # ---- 显示 ----

    def __repr__(self) -> str:
        return f'FieldExpr({self.model_class.__name__}.{self.field_name})'

    def __str__(self) -> str:
        return self._django_name


class _JsonKeyExpression:
    """JSON 字段键表达式，由 ``Model.json_field['key']`` 产生。"""

    def __init__(self, field_name: str, key: str) -> None:
        self.field_name = field_name
        self.key = key

    def _lookup(self, suffix: str = '') -> str:
        if suffix:
            return f'{self.field_name}__{self.key}__{suffix}'
        return f'{self.field_name}__{self.key}'

    def cast(self, type_hint) -> _CastJsonExpression:
        """将 JSON 值转换为指定类型后再比较。"""
        return _CastJsonExpression(self.field_name, self.key, type_hint)

    def __eq__(self, other) -> Q:  # type: ignore[override]
        return Q(**{self._lookup(): other})

    def __ne__(self, other) -> Q:  # type: ignore[override]
        return ~Q(**{self._lookup(): other})

    def __gt__(self, other) -> Q:
        return Q(**{self._lookup('gt'): other})

    def __ge__(self, other) -> Q:
        return Q(**{self._lookup('gte'): other})

    def __lt__(self, other) -> Q:
        return Q(**{self._lookup('lt'): other})

    def __le__(self, other) -> Q:
        return Q(**{self._lookup('lte'): other})

    def between(self, low, high) -> Q:
        return Q(**{self._lookup('gte'): low}) & Q(**{self._lookup('lte'): high})

    def __repr__(self) -> str:
        return f'JsonKeyExpr({self.field_name}[{self.key!r}])'


class _CastJsonExpression:
    """类型转换后的 JSON 键表达式。"""

    def __init__(self, field_name: str, key: str, type_hint) -> None:
        self.field_name = field_name
        self.key = key
        self.type_hint = type_hint

    def _lookup(self, suffix: str = '') -> str:
        if suffix:
            return f'{self.field_name}__{self.key}__{suffix}'
        return f'{self.field_name}__{self.key}'

    def __eq__(self, other) -> Q:  # type: ignore[override]
        return Q(**{self._lookup(): other})

    def __ne__(self, other) -> Q:  # type: ignore[override]
        return ~Q(**{self._lookup(): other})

    def __gt__(self, other) -> Q:
        return Q(**{self._lookup('gt'): other})

    def __ge__(self, other) -> Q:
        return Q(**{self._lookup('gte'): other})

    def __lt__(self, other) -> Q:
        return Q(**{self._lookup('lt'): other})

    def __le__(self, other) -> Q:
        return Q(**{self._lookup('lte'): other})

    def between(self, low, high) -> Q:
        return Q(**{self._lookup('gte'): low}) & Q(**{self._lookup('lte'): high})

    def __repr__(self) -> str:
        type_name = getattr(self.type_hint, '__name__', str(self.type_hint))
        return f'CastJsonExpr({self.field_name}[{self.key!r}]->{type_name})'


# ---------------------------------------------------------------------------
# QModel 元类与基类
# ---------------------------------------------------------------------------

class QModelBase(models.base.ModelBase):
    """QModel 元类，负责：

    1. 根据 ``GVSDSDK_MANAGE_TABLES`` 设置动态控制 ``managed``
    2. 包装字段描述符，使类级别访问返回 FieldExpression
    """

    def __new__(mcs, name, bases, namespace, **kwargs):
        # 动态设置 managed：子服务器可设 GVSDSDK_MANAGE_TABLES=True 让 gvsdsdk 管理表
        meta = namespace.get('Meta')
        if meta and getattr(meta, 'app_label', None) == 'gvsdsdk':
            try:
                from django.conf import settings
                if getattr(settings, 'GVSDSDK_MANAGE_TABLES', False):
                    meta.managed = True
            except Exception:
                pass

        cls = super().__new__(mcs, name, bases, namespace, **kwargs)

        # 模型创建后，包装字段描述符以支持类级别 FieldExpression
        if not cls._meta.abstract:
            _wrap_field_descriptors(cls)

        return cls


def _wrap_field_descriptors(cls: Type) -> None:
    """包装 Django 字段描述符，使类级别访问返回 FieldExpression，
    实例级别完全委托给 Django 原生描述符。

    Django 的字段描述符（DeferredAttribute / ForwardManyToOneDescriptor）：
    - ``__get__(None, cls)`` → 返回字段对象本身（类级别）
    - ``__get__(instance, cls)`` → 返回字段值（实例级别）

    我们包装后：
    - ``__get__(None, cls)`` → 返回 FieldExpression（类级别，用于链式 OOP）
    - ``__get__(instance, cls)`` → 委托给原生描述符（实例级别，正常行为）
    """
    from django.db.models.query_utils import DeferredAttribute
    from django.db.models.fields.related_descriptors import (
        ForwardManyToOneDescriptor,
        ForwardOneToOneDescriptor,
    )

    for field in cls._meta.local_fields:
        fname = field.name
        if fname.startswith('_'):
            continue

        original_desc = cls.__dict__.get(fname)
        if original_desc is None:
            continue

        # 只包装已知的 Django 描述符类型
        if isinstance(original_desc, (DeferredAttribute, ForwardManyToOneDescriptor,
                                       ForwardOneToOneDescriptor)):
            wrapper = _FieldExpressionWrapper(original_desc, cls, fname)
            setattr(cls, fname, wrapper)


class _FieldExpressionWrapper:
    """包装 Django 字段描述符，类级别返回 FieldExpression，实例级别委托给原生描述符。

    这是 QModel 字段表达式机制的核心：当你在类上访问 ``Model.field_name`` 时，
    返回 ``FieldExpression`` 对象，支持 ``Model.field == value`` 等运算符构建 Q 对象；
    当你在实例上访问 ``obj.field_name`` 时，行为与原生 Django 完全一致。
    """

    def __init__(self, original_descriptor, model_class: Type, field_name: str) -> None:
        self._original = original_descriptor
        self._model = model_class
        self._field_name = field_name
        self._has_set: bool = hasattr(original_descriptor, '__set__')

    def __get__(self, obj, objtype=None):
        if obj is None:
            # 类级别访问：返回 FieldExpression
            return FieldExpression(self._model, self._field_name)
        # 实例级别访问：委托给原生 Django 描述符
        return self._original.__get__(obj, objtype)

    def __set__(self, obj, value) -> None:
        if self._has_set:
            # FK/O2O 描述符有 __set__
            self._original.__set__(obj, value)
        else:
            # 普通字段（DeferredAttribute）没有 __set__，直接写 __dict__
            obj.__dict__[self._field_name] = value

    def __repr__(self) -> str:
        return f'_FieldExpressionWrapper({self._model.__name__}.{self._field_name})'


class QModel(models.Model, metaclass=QModelBase):
    """QModel 兼容层基类，提供 SQLAlchemy 风格的链式 OOP 查询接口。

    所有继承 QModel 的模型自动获得：

    - ``Model.query`` : 返回 FluentQuery，支持链式查询
    - ``Model.field_name`` : 类级别访问返回 FieldExpression，支持表达式查询
    - ``Model.field_name`` : 实例级别访问返回字段值（与普通 Django Model 一致）
    - ``Model[condition]`` : 快捷 filter 语法

    用法示例::

        # 链式查询
        orders = Dingdan.query.filter(zhuangtai=8).order_by('-CreateTime').to_list()

        # 字段表达式
        Dingdan.query.filter(Dingdan.jine > 100, Dingdan.zhuangtai.in_([1,2,3]))

        # 聚合
        Dingdan.query.aggregate(total=Sum('jine'))

        # values / annotate
        Dingdan.query.values('zhuangtai').annotate(cnt=Count('id'))

        # 分页
        Dingdan.query.paginate(page=1, per_page=20)

        # 快捷 filter
        Dingdan[Dingdan.zhuangtai == 8].order_by('-CreateTime').to_list()
    """

    class Meta:
        abstract = True

    @classproperty
    def query(cls) -> FluentQuery[Self]:
        """返回 FluentQuery 兼容层查询构建器，支持链式 OOP 查询。"""
        return FluentQuery(cls)

    @classmethod
    def __class_getitem__(cls, item) -> FluentQuery[Self]:
        """支持 ``Model[condition]`` 语法，返回 filter 后的 FluentQuery。

        用法::

            Dingdan[Dingdan.zhuangtai == 8].order_by('-CreateTime').to_list()
            Dingdan[{'zhuangtai': 8}].to_list()
        """
        if isinstance(item, Q):
            return cls.query.filter(item)
        if isinstance(item, dict):
            return cls.query.filter(**item)
        return cls.query.filter(item)
