from datetime import datetime
from typing import List, Dict, Any, Tuple, Callable, Optional

from sqlalchemy.orm import Session


class RelateUpsert:
    """一对多关系同步管理器"""

    @staticmethod
    def relate_upsert(
            session: Session,
            parent_id_field: str,
            parent_id_value: Any,
            model_class: type,
            new_records: List[Dict[str, Any]],
            unique_keys: Tuple[str, ...],
            soft_delete: bool = True,
            delete_field: str = "is_deleted",
            update_callback: Optional[Callable] = None,
            exclude_fields: Optional[List[str]] = None
    ):
        """
        通用的一对多关系同步

        Args:
            session: 数据库会话
            parent_id_field: 父表ID字段名
            parent_id_value: 父表ID值
            model_class: ORM模型类
            new_records: 新的记录列表
            unique_keys: 唯一键字段元组
            soft_delete: 是否软删除
            delete_field: 软删除字段名
            update_callback: 自定义更新回调
            exclude_fields: 更新时排除的字段
        """
        exclude_fields = exclude_fields or []

        # 构建查询条件
        query_filter = {parent_id_field: parent_id_value}
        if soft_delete:
            query_filter[delete_field] = False

        # 获取现有记录
        existing_records = session.query(model_class).filter_by(**query_filter).all()

        # 构建键映射
        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(record): record for record in existing_records}
        existing_keys = set(existing_dict.keys())
        new_keys = {make_key(record) for record in new_records}

        # 删除操作
        to_delete_keys = existing_keys - new_keys
        for key in to_delete_keys:
            record = existing_dict[key]
            if soft_delete:
                setattr(record, delete_field, True)
                if hasattr(record, 'deleted_at'):
                    setattr(record, 'deleted_at', datetime.now())
            else:
                session.delete(record)

        # 更新或新增
        for new_data in new_records:
            key = make_key(new_data)

            if key in existing_dict:
                # 更新
                existing_record = existing_dict[key]

                if update_callback:
                    update_callback(existing_record, new_data)
                else:
                    for field, value in new_data.items():
                        if (field not in unique_keys
                                and field not in exclude_fields
                                and hasattr(existing_record, field)):
                            setattr(existing_record, field, value)

                if hasattr(existing_record, 'updated_at'):
                    setattr(existing_record, 'updated_at', datetime.now())
            else:
                # 新增
                new_record = model_class(**{parent_id_field: parent_id_value, **new_data})
                session.add(new_record)
        session.flush()
