from typing import List, Dict, Any, Tuple, Optional, Callable
from datetime import datetime
from sqlalchemy.orm import Session


class RelateUpsertMixin:
    """
    子表 CRUD Mixin，支持一对多关系批量同步（relate_upsert）。
    """

    def relate_upsert(
            self,
            session: Session,
            parent_id_field: str,
            parent_id_value: Any,
            new_records: List[Dict[str, Any]],
            unique_keys: Tuple[str, ...],
            soft_delete: bool = True,
            delete_field: str = "is_deleted",
            update_callback: Optional[Callable[[Any, Dict[str, Any]], None]] = None,
            exclude_fields: Optional[List[str]] = None,
    ):
        """
        批量同步子表数据，自动处理更新、新增、删除（软/硬删除）。

        Args:
            session: SQLAlchemy Session
            parent_id_field: 父表ID字段名
            parent_id_value: 父表ID值
            new_records: 新的记录列表
            unique_keys: 用于匹配的唯一键字段元组
            soft_delete: 是否软删除缺失记录
            delete_field: 软删除字段名
            update_callback: 自定义更新回调，签名(update_obj, new_data)
            exclude_fields: 更新时排除的字段
        """
        exclude_fields = exclude_fields or []

        # 1️⃣ 查询现有记录
        query_filter = {parent_id_field: parent_id_value}
        # if soft_delete:
        #     query_filter[delete_field] = False

        existing_records = session.query(self.model).filter_by(**query_filter).all()

        # 2️⃣ 构建键映射
        def make_key(record_data):
            if isinstance(record_data, dict):
                return tuple(record_data.get(k) for k in unique_keys)
            return tuple(getattr(record_data, k) for k in unique_keys)

        existing_dict = {make_key(rec): rec for rec in existing_records}
        existing_keys = set(existing_dict.keys())
        new_keys = {make_key(rec) for rec in new_records}

        # 3️⃣ 删除缺失记录
        to_delete_keys = existing_keys - new_keys
        for key in to_delete_keys:
            record = existing_dict[key]
            if soft_delete:
                if hasattr(record, delete_field) and getattr(record, delete_field):
                    continue
                setattr(record, delete_field, True)
                if hasattr(record, 'deleted_at'):
                    setattr(record, 'deleted_at', datetime.now())
            else:
                session.delete(record)

        # 4️⃣ 更新或新增
        for new_data in new_records:
            key = make_key(new_data)
            if key in existing_dict:
                obj = existing_dict[key]
                if hasattr(obj, delete_field) and getattr(obj, delete_field):
                    setattr(obj, delete_field, False)
                if update_callback:
                    update_callback(obj, new_data)
                else:
                    for field, value in new_data.items():
                        if field not in unique_keys and field not in exclude_fields and hasattr(obj, field):
                            setattr(obj, field, value)
                if hasattr(obj, 'updated_at'):
                    setattr(obj, 'updated_at', datetime.now())
            else:
                obj = self.model(**{parent_id_field: parent_id_value, **new_data})
                session.add(obj)

        # 5️⃣ flush 不 commit，由 Service 层控制事务
        session.flush()

        # 6️⃣ 返回最新对象列表
        return session.query(self.model).filter(
            getattr(self.model, parent_id_field) == parent_id_value
        ).all()
