# db_storage.py
import json
import sqlite3
import time
import logging
import random
import threading
from queue import Queue, Empty
from typing import Dict, Any, Optional
from chat import get_game_db, close_game_connection
from combat import generate_uuid

_db_write_lock = threading.Lock()
logger = logging.getLogger(__name__)
_save_queue = Queue(maxsize=1000)
_save_worker_started = False

def async_save_state(char_id, user_id, name, state):
    """异步保存玩家状态"""
    _save_queue.put((char_id, user_id, name, state.copy()))

def _save_worker():
    """后台保存线程"""
    while True:
        try:
            char_id, user_id, name, state = _save_queue.get(timeout=1)
            _do_save_state(char_id, user_id, name, state)
        except Empty:
            continue
        except Exception as e:
            logger.error(f"异步保存失败: {e}")

def _do_save_state(char_id, user_id, name, state):
    save_state_to_tables(char_id, user_id, name, state)

def start_async_save_worker():
    global _save_worker_started
    if not _save_worker_started:
        threading.Thread(target=_save_worker, daemon=True).start()
        _save_worker_started = True

def _dict_to_json(obj: Any) -> str:
    return json.dumps(obj, ensure_ascii=False)

def _json_to_dict(s: Optional[str]) -> Any:
    return json.loads(s) if s else None

def save_state_to_tables(char_id: int, user_id: int, name: str, state: Dict):
    with _db_write_lock:
        conn = get_game_db()
        try:
            c = conn.cursor()
            player = state.get('player', {})
            c.execute('''
                INSERT OR REPLACE INTO players 
                (id, user_id, name, level, exp, max_exp, hp, max_hp, mp, max_mp,
                 attack_min, attack_max, defense_min, defense_max, rebirth, gold,
                 attack_enhance, defense_enhance, exp_multiplier, game_speed, skills,
                 accuracy, dodge, avatar, warehouse_unlocked, max_inventory_slots,
                 max_warehouse_slots, created_at, config_json,
                 current_map, current_monster, monster_burn_turns, save_time,
                 crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                char_id, user_id, name,
                player.get('level'), player.get('exp'), player.get('maxExp'),
                player.get('hp'), player.get('maxHp'), player.get('mp'), player.get('maxMp'),
                player.get('attackMin'), player.get('attackMax'), player.get('defenseMin'), player.get('defenseMax'),
                player.get('rebirth'), player.get('gold'),
                player.get('attackEnhance'), player.get('defenseEnhance'),
                player.get('expMultiplier'), player.get('gameSpeed'),
                _pack_skills(player.get('skills', [])),
                player.get('accuracy'), player.get('dodge'), player.get('avatar', ''),
                1 if state.get('warehouseUnlocked') else 0,
                state.get('maxInventorySlots', 500), state.get('maxWarehouseSlots', 500),
                state.get('saveTime', int(time.time())),
                _dict_to_json(state.get('autoSellConfig', {'selectedSets': [], 'qualityMap': {}})),
                state.get('currentMap', 1),
                state.get('currentMonster', 1),
                state.get('monsterBurnTurns', 0),
                state.get('saveTime', int(time.time())),
                player.get('critRate', 0),
                player.get('critDamage', 1.5),
                player.get('lethalRate', 0),
                player.get('lethalDamage', 3.0),
                player.get('poisonRate', 0),
                player.get('poisonDamage', 0)
            ))
            
            # 2. 英雄表
            hero = state.get('hero', {})
            if hero.get('summoned'):
                hero.setdefault('level', 1)
                hero.setdefault('exp', 0)
                hero.setdefault('maxExp', 100)
                hero.setdefault('hp', 80)
                hero.setdefault('maxHp', 80)
                hero.setdefault('mp', 40)
                hero.setdefault('maxMp', 40)
                hero.setdefault('attackMin', 4)
                hero.setdefault('attackMax', 8)
                hero.setdefault('defenseMin', 1)
                hero.setdefault('defenseMax', 3)
                hero.setdefault('rebirth', 0)
                hero.setdefault('attackEnhance', 0)
                hero.setdefault('defenseEnhance', 0)
                hero.setdefault('expMultiplier', 1.0)
                hero.setdefault('gameSpeed', 1.0)
                hero.setdefault('accuracy', 1)
                hero.setdefault('dodge', 1)
                hero.setdefault('avatar', '')
                hero.setdefault('critRate', 0.0)
                hero.setdefault('critDamage', 1.5)
                hero.setdefault('lethalRate', 0.0)
                hero.setdefault('lethalDamage', 3.0)
                hero.setdefault('poisonRate', 0.0)
                hero.setdefault('poisonDamage', 0)

                c.execute('''
                    INSERT OR REPLACE INTO heroes
                    (player_id, summoned, level, exp, max_exp, hp, max_hp, mp, max_mp,
                     attack_min, attack_max, defense_min, defense_max, rebirth,
                     attack_enhance, defense_enhance, exp_multiplier, game_speed, skills,
                     accuracy, dodge, avatar,
                     crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ''', (
                    char_id, 1,
                    hero['level'], hero['exp'], hero['maxExp'],
                    hero['hp'], hero['maxHp'], hero['mp'], hero['maxMp'],
                    hero['attackMin'], hero['attackMax'], hero['defenseMin'], hero['defenseMax'],
                    hero['rebirth'], hero['attackEnhance'], hero['defenseEnhance'],
                    hero['expMultiplier'], hero['gameSpeed'],
                    _pack_skills(hero.get('skills', [])),
                    hero['accuracy'], hero['dodge'], hero['avatar'],
                    hero['critRate'], hero['critDamage'], hero['lethalRate'],
                    hero['lethalDamage'], hero['poisonRate'], hero['poisonDamage']
                ))
            else:
                c.execute('DELETE FROM heroes WHERE player_id = ?', (char_id,))
            
            # 3. 背包
            c.execute('DELETE FROM inventory WHERE player_id = ?', (char_id,))
            for item in state.get('inventory', []):
                c.execute('''
                    INSERT INTO inventory
                    (player_id, uuid, item_id, name, type, quantity, enhance_level, quality, data,
                     acquired_time, dropped_by)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ''', (
                    char_id, item.get('uuid'), item.get('id'), item.get('name'), item.get('type'),
                    item.get('quantity', 1), item.get('enhanceLevel', 0), item.get('quality'),
                    _dict_to_json({k: v for k, v in item.items() if k not in ('uuid', 'id', 'name', 'type', 'quantity', 'enhanceLevel', 'quality', 'acquiredTime', 'droppedBy')}),
                    item.get('acquiredTime'), item.get('droppedBy')
                ))
            
            # 4. 仓库
            c.execute('DELETE FROM warehouse WHERE player_id = ?', (char_id,))
            for item in state.get('warehouse', []):
                c.execute('''
                    INSERT INTO warehouse
                    (player_id, uuid, item_id, name, type, quantity, enhance_level, quality, data,
                     acquired_time, dropped_by)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ''', (char_id, item.get('uuid'), item.get('id'), item.get('name'), item.get('type'),
                      item.get('quantity', 1), item.get('enhanceLevel', 0), item.get('quality'),
                      _dict_to_json({k: v for k, v in item.items() if k not in ('uuid', 'id', 'name', 'type', 'quantity', 'enhanceLevel', 'quality', 'acquiredTime', 'droppedBy')}),
                      item.get('acquiredTime'), item.get('droppedBy')))
            
            # 5. 玩家装备
            c.execute('DELETE FROM player_equipment WHERE player_id = ?', (char_id,))
            equip_player = state.get('equipment', {}).get('player', {})
            for slot, item in equip_player.items():
                if item:
                    c.execute('''
                        INSERT INTO player_equipment (player_id, slot, item_uuid, data)
                        VALUES (?, ?, ?, ?)
                    ''', (char_id, slot, item.get('uuid'), _dict_to_json(item)))
            
            # 6. 英雄装备
            c.execute('DELETE FROM hero_equipment WHERE player_id = ?', (char_id,))
            equip_hero = state.get('equipment', {}).get('hero', {})
            for slot, item in equip_hero.items():
                if item:
                    c.execute('''
                        INSERT INTO hero_equipment (player_id, slot, item_uuid, data)
                        VALUES (?, ?, ?, ?)
                    ''', (char_id, slot, item.get('uuid'), _dict_to_json(item)))
            
            # 7. 任务
            task = state.get('task', {})
            c.execute('''
                INSERT OR REPLACE INTO tasks
                (player_id, completed_count, points, last_reset_date, last_abandoned, current_task)
                VALUES (?, ?, ?, ?, ?, ?)
            ''', (char_id, task.get('completedCount', 0), task.get('points', 0),
                  task.get('lastResetDate'), task.get('lastAbandoned', 0),
                  _dict_to_json(task.get('currentTask'))))
            
            # 8. 农场
            farm = state.get('farm', {})
            c.execute('''
                INSERT OR REPLACE INTO farms (player_id, plots, unlocked_plots)
                VALUES (?, ?, ?)
            ''', (char_id, _dict_to_json(farm.get('plots', [])), farm.get('unlocked_plots', 0)))
            
            # 9. 十二生肖
            c.execute('DELETE FROM zodiac_equipped WHERE player_id = ?', (char_id,))
            for zodiac_id_str, item in state.get('zodiac_equipped', {}).items():
                try:
                    zodiac_id = int(zodiac_id_str)
                except (ValueError, TypeError):
                    zodiac_id = zodiac_id_str
                c.execute('''
                    INSERT INTO zodiac_equipped (player_id, zodiac_id, zodiac_uuid, slot_index, data)
                    VALUES (?, ?, ?, ?, ?)
                ''', (char_id, zodiac_id, item.get('uuid'), None, _dict_to_json(item)))
            
            # 10. 种子仓库
            c.execute('DELETE FROM seed_storage WHERE player_id = ?', (char_id,))
            for seed in state.get('seed_storage', []):
                c.execute('''
                    INSERT INTO seed_storage (player_id, seed_uuid, name, quantity, data)
                    VALUES (?, ?, ?, ?, ?)
                ''', (char_id, seed.get('uuid'), seed.get('name'), seed.get('quantity', 1),
                      _dict_to_json({k: v for k, v in seed.items() if k not in ('uuid', 'name', 'quantity')})))
            
            # 11. 临时增益（修改后）
            c.execute('DELETE FROM temporary_buffs WHERE player_id = ?', (char_id,))
            now = int(time.time())
            for unique_id, buff_data in state.get('temporary_buffs', {}).items():
                target = buff_data.get('target', 'player')
                attrs = buff_data.get('attributes', {})
                if not attrs:
                    continue
                buff_type = next(iter(attrs.keys()))
                value = attrs[buff_type]
                expire_time = buff_data.get('expire_time')
                if expire_time is None:
                    start = buff_data.get('start_time')
                    duration = buff_data.get('duration')
                    if start is not None and duration is not None:
                        expire_time = start + duration
                    elif duration is not None:
                        expire_time = now + duration
                    else:
                        continue
                source = buff_data.get('source', 'normal')
                c.execute('''
                    INSERT INTO temporary_buffs 
                    (player_id, buff_type, value, expire_time, target, source, unique_id)
                    VALUES (?, ?, ?, ?, ?, ?, ?)
                ''', (char_id, buff_type, value, expire_time, target, source, unique_id))
            
            # 12. 写入 player_combat 表
            c.execute('INSERT OR REPLACE INTO player_combat (player_id, current_combat, monster_group) VALUES (?, ?, ?)',
                      (char_id, _dict_to_json(state.get('currentCombat', {})), _dict_to_json(state.get('monsterGroup', None))))

            conn.commit()
        except Exception as e:
            conn.rollback()
            logger.error(f"保存分表数据失败 {name}: {e}")
            raise
        finally:
            close_game_connection(conn)

def _pack_skills(skills_list):
    """将技能对象列表压缩为 [{id, enhance_level, proficiency}] 格式"""
    if not skills_list:
        return '[]'
    packed = []
    for sk in skills_list:
        if isinstance(sk, dict):
            skill_id = sk.get('id')
            if skill_id is None:
                continue
            packed.append({
                "id": skill_id,
                "enhance_level": sk.get("enhance_level", 0),
                "proficiency": sk.get("proficiency", 0)
            })
        else:
            packed.append({"id": sk, "enhance_level": 0, "proficiency": 0})
    return json.dumps(packed, ensure_ascii=False)

def _unpack_skills(skills_json, target='player'):
    """将轻量技能数据还原为完整技能对象（合并静态属性）"""
    if not skills_json:
        return []
    raw = json.loads(skills_json)
    if not isinstance(raw, list):
        return []
    from static_db import db
    static = db.get_skills()
    if target == 'player':
        skill_map = {s['id']: s for s in static.get('playerSkills', [])}
    else:
        skill_map = {s['id']: s for s in static.get('heroSkills', [])}

    result = []
    for entry in raw:
        if isinstance(entry, dict):
            skill_id = entry.get('id')
            if skill_id is None:
                continue
            base = skill_map.get(skill_id)
            if not base:
                continue   # 技能已被删除，跳过
            full = base.copy()
            full['enhance_level'] = entry.get('enhance_level', 0)
            full['proficiency'] = entry.get('proficiency', 0)
            result.append(full)
        else:
            result.append(entry)
    return result
            
def load_state_from_tables(name: str) -> Optional[Dict]:
    """从分表读取玩家状态，组装成完整的 state 字典"""
    conn = get_game_db()
    try:
        c = conn.cursor()
        # 获取玩家基本信息（包含新列）
        c.execute('''
            SELECT id, user_id, name, level, exp, max_exp, hp, max_hp, mp, max_mp,
                   attack_min, attack_max, defense_min, defense_max, rebirth, gold,
                   attack_enhance, defense_enhance, exp_multiplier, game_speed, skills,
                   accuracy, dodge, avatar, warehouse_unlocked, max_inventory_slots,
                   max_warehouse_slots, created_at, config_json,
                   current_map, current_monster, monster_burn_turns, save_time,
                   crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage
            FROM players WHERE name = ?
        ''', (name,))
        row = c.fetchone()
        if not row:
            return None
        (char_id, user_id, name, level, exp, max_exp, hp, max_hp, mp, max_mp,
         attack_min, attack_max, defense_min, defense_max, rebirth, gold,
         attack_enhance, defense_enhance, exp_multiplier, game_speed, skills_json,
         accuracy, dodge, avatar, warehouse_unlocked, max_inv_slots, max_ware_slots,
         created_at, config_json,
         current_map, current_monster, monster_burn_turns, save_time,
         crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage) = row

        state = {
            "player": {
                "name": name,
                "level": level, "exp": exp, "maxExp": max_exp,
                "hp": hp, "maxHp": max_hp, "mp": mp, "maxMp": max_mp,
                "attackMin": attack_min, "attackMax": attack_max,
                "defenseMin": defense_min, "defenseMax": defense_max,
                "rebirth": rebirth, "gold": gold,
                "attackEnhance": attack_enhance, "defenseEnhance": defense_enhance,
                "expMultiplier": exp_multiplier, "gameSpeed": game_speed,
                "skills": _unpack_skills(skills_json, target='player'),
                "accuracy": accuracy, "dodge": dodge, "avatar": avatar,
                "critRate": crit_rate,
                "critDamage": crit_damage,
                "lethalRate": lethal_rate,
                "lethalDamage": lethal_damage,
                "poisonRate": poison_rate,
                "poisonDamage": poison_damage
            },
            "hero": {},
            "inventory": [],
            "warehouse": [],
            "equipment": {"player": {}, "hero": {}},
            "currentMap": current_map,
            "currentMonster": current_monster,
            "currentCombat": {},
            "monsterBurnTurns": monster_burn_turns,
            "maxInventorySlots": max_inv_slots,
            "maxWarehouseSlots": max_ware_slots,
            "warehouseUnlocked": bool(warehouse_unlocked),
            "userId": user_id,
            "saveTime": created_at,
            "task": {},
            "temporary_buffs": {},
            "zodiac_equipped": {},
            "seed_storage": [],
            "farm": {},
            "uuid_migrated": True
        }
        
        # 读取英雄
        c.execute('SELECT * FROM heroes WHERE player_id = ? AND summoned = 1', (char_id,))
        hero_row = c.fetchone()
        if hero_row:
            state["hero"] = {
                "summoned": True,
                "level": hero_row[3], "exp": hero_row[4], "maxExp": hero_row[5],
                "hp": hero_row[6], "maxHp": hero_row[7], "mp": hero_row[8], "maxMp": hero_row[9],
                "attackMin": hero_row[10], "attackMax": hero_row[11],
                "defenseMin": hero_row[12], "defenseMax": hero_row[13],
                "rebirth": hero_row[14],
                "attackEnhance": hero_row[15], "defenseEnhance": hero_row[16],
                "expMultiplier": hero_row[17], "gameSpeed": hero_row[18],
                "skills": _unpack_skills(hero_row[19], target='hero'),
                "accuracy": hero_row[20], "dodge": hero_row[21], "avatar": hero_row[22],
                "critRate": hero_row[23], "critDamage": hero_row[24],
                "lethalRate": hero_row[25], "lethalDamage": hero_row[26],
                "poisonRate": hero_row[27], "poisonDamage": hero_row[28]
            }
        else:
            state["hero"] = {"summoned": False}
            
        c.execute('SELECT current_combat, monster_group FROM player_combat WHERE player_id = ?', (char_id,))
        combat_row = c.fetchone()
        if combat_row:
            state['currentCombat'] = _json_to_dict(combat_row[0]) or {}
            state['monsterGroup'] = _json_to_dict(combat_row[1])
        else:
            state['currentCombat'] = {}
            state['monsterGroup'] = None
        
        # 背包
        c.execute('SELECT * FROM inventory WHERE player_id = ?', (char_id,))
        for item in c.fetchall():
            inv_item = {
                "uuid": item[2], "id": item[3], "name": item[4], "type": item[5],
                "quantity": item[6], "enhanceLevel": item[7], "quality": item[8],
                "acquiredTime": item[10], "droppedBy": item[11]
            }
            extra = _json_to_dict(item[9])
            if extra:
                inv_item.update(extra)
            state["inventory"].append(inv_item)
        
        # 仓库
        c.execute('SELECT * FROM warehouse WHERE player_id = ?', (char_id,))
        for item in c.fetchall():
            ware_item = {
                "uuid": item[2], "id": item[3], "name": item[4], "type": item[5],
                "quantity": item[6], "enhanceLevel": item[7], "quality": item[8],
                "acquiredTime": item[10], "droppedBy": item[11]
            }
            extra = _json_to_dict(item[9])
            if extra:
                ware_item.update(extra)
            state["warehouse"].append(ware_item)
        
        # 玩家装备
        c.execute('SELECT slot, data FROM player_equipment WHERE player_id = ?', (char_id,))
        for slot, data_json in c.fetchall():
            if data_json:
                state["equipment"]["player"][slot] = _json_to_dict(data_json)
        
        # 英雄装备
        c.execute('SELECT slot, data FROM hero_equipment WHERE player_id = ?', (char_id,))
        for slot, data_json in c.fetchall():
            if data_json:
                state["equipment"]["hero"][slot] = _json_to_dict(data_json)
        
        # 任务
        c.execute('SELECT * FROM tasks WHERE player_id = ?', (char_id,))
        task_row = c.fetchone()
        if task_row:
            state["task"] = {
                "completedCount": task_row[1],
                "points": task_row[2],
                "lastResetDate": task_row[3],
                "lastAbandoned": task_row[4],
                "currentTask": _json_to_dict(task_row[5])
            }
        
        # 农场
        c.execute('SELECT plots, unlocked_plots FROM farms WHERE player_id = ?', (char_id,))
        farm_row = c.fetchone()
        if farm_row:
            state["farm"] = {
                "plots": _json_to_dict(farm_row[0]) or [],
                "unlocked_plots": farm_row[1]
            }
        
        # 十二生肖
        c.execute('SELECT zodiac_id, data FROM zodiac_equipped WHERE player_id = ?', (char_id,))
        for z_id, data_json in c.fetchall():
            if data_json:
                item = _json_to_dict(data_json)
                if item and 'uuid' in item:
                    state["zodiac_equipped"][str(z_id)] = item
                else:
                    logger.warning(f"玩家 {name} 的生肖 {z_id} 数据无效，已忽略")
            else:
                c.execute('SELECT zodiac_uuid FROM zodiac_equipped WHERE player_id = ? AND zodiac_id = ?', (char_id, z_id))
                row2 = c.fetchone()
                if row2:
                    from zodiac import zodiac_manager
                    full_item = zodiac_manager.create_zodiac_item(z_id)
                    if full_item:
                        full_item['uuid'] = row2[0]
                        state["zodiac_equipped"][str(z_id)] = full_item
                        logger.info(f"为玩家 {name} 从配置重建生肖 {z_id}")
                    else:
                        logger.warning(f"无法重建生肖 {z_id}，配置中不存在")
        
        # 种子仓库
        c.execute('SELECT seed_uuid, name, quantity, data FROM seed_storage WHERE player_id = ?', (char_id,))
        for seed_uuid, name, qty, data_json in c.fetchall():
            seed = {"uuid": seed_uuid, "name": name, "quantity": qty}
            extra = _json_to_dict(data_json)
            if extra:
                seed.update(extra)
            state["seed_storage"].append(seed)
        
        # 临时增益
        c.execute('SELECT buff_type, value, expire_time, target, source, unique_id FROM temporary_buffs WHERE player_id = ?', (char_id,))
        now = int(time.time())
        state['temporary_buffs'] = {}
        for buff_type, value, expire, target, source, unique_id in c.fetchall():
            if expire and expire > now:
                key = unique_id if unique_id else f"{buff_type}_{target}_{expire}_{random.randint(0, 10000)}"
                state['temporary_buffs'][key] = {
                    'target': target,
                    'attributes': {buff_type: value},
                    'expire_time': expire,
                    'source': source,
                    'duration': expire - now,
                    'start_time': now
                }
        state['autoSellConfig'] = _json_to_dict(config_json) or {'selectedSets': [], 'qualityMap': {}}
        return state
    except Exception as e:
        logger.error(f"从分表加载角色 {name} 失败: {e}")
        return None
    finally:
        close_game_connection(conn)
        
def save_state_to_tables_with_conn(conn, char_id, user_id, name, state):
    try:
        c = conn.cursor()
        # 1. 写入 players 表
        player = state.get('player', {})
        c.execute('''
            INSERT OR REPLACE INTO players 
            (id, user_id, name, level, exp, max_exp, hp, max_hp, mp, max_mp,
             attack_min, attack_max, defense_min, defense_max, rebirth, gold,
             attack_enhance, defense_enhance, exp_multiplier, game_speed, skills,
             accuracy, dodge, avatar, warehouse_unlocked, max_inventory_slots,
             max_warehouse_slots, created_at, config_json,
             current_map, current_monster, monster_burn_turns, save_time,
             crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ''', (
            char_id, user_id, name,
            player.get('level'), player.get('exp'), player.get('maxExp'),
            player.get('hp'), player.get('maxHp'), player.get('mp'), player.get('maxMp'),
            player.get('attackMin'), player.get('attackMax'), player.get('defenseMin'), player.get('defenseMax'),
            player.get('rebirth'), player.get('gold'),
            player.get('attackEnhance'), player.get('defenseEnhance'),
            player.get('expMultiplier'), player.get('gameSpeed'),
            _pack_skills(player.get('skills', [])),
            player.get('accuracy'), player.get('dodge'), player.get('avatar', ''),
            1 if state.get('warehouseUnlocked') else 0,
            state.get('maxInventorySlots', 500), state.get('maxWarehouseSlots', 500),
            state.get('saveTime', int(time.time())),
            _dict_to_json(state.get('autoSellConfig', {'selectedSets': [], 'qualityMap': {}})),
            state.get('currentMap', 1),
            state.get('currentMonster', 1),
            state.get('monsterBurnTurns', 0),
            state.get('saveTime', int(time.time())),
            player.get('critRate', 0),
            player.get('critDamage', 1.5),
            player.get('lethalRate', 0),
            player.get('lethalDamage', 3.0),
            player.get('poisonRate', 0),
            player.get('poisonDamage', 0)
        ))

        # 2. 英雄表
        hero = state.get('hero', {})
        if hero.get('summoned'):
            hero.setdefault('level', 1)
            hero.setdefault('exp', 0)
            hero.setdefault('maxExp', 100)
            hero.setdefault('hp', 80)
            hero.setdefault('maxHp', 80)
            hero.setdefault('mp', 40)
            hero.setdefault('maxMp', 40)
            hero.setdefault('attackMin', 4)
            hero.setdefault('attackMax', 8)
            hero.setdefault('defenseMin', 1)
            hero.setdefault('defenseMax', 3)
            hero.setdefault('rebirth', 0)
            hero.setdefault('attackEnhance', 0)
            hero.setdefault('defenseEnhance', 0)
            hero.setdefault('expMultiplier', 1.0)
            hero.setdefault('gameSpeed', 1.0)
            hero.setdefault('accuracy', 1)
            hero.setdefault('dodge', 1)
            hero.setdefault('avatar', '')
            hero.setdefault('critRate', 0.0)
            hero.setdefault('critDamage', 1.5)
            hero.setdefault('lethalRate', 0.0)
            hero.setdefault('lethalDamage', 3.0)
            hero.setdefault('poisonRate', 0.0)
            hero.setdefault('poisonDamage', 0)

            c.execute('''
                INSERT OR REPLACE INTO heroes
                (player_id, summoned, level, exp, max_exp, hp, max_hp, mp, max_mp,
                 attack_min, attack_max, defense_min, defense_max, rebirth,
                 attack_enhance, defense_enhance, exp_multiplier, game_speed, skills,
                 accuracy, dodge, avatar,
                 crit_rate, crit_damage, lethal_rate, lethal_damage, poison_rate, poison_damage)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                char_id, 1,
                hero['level'], hero['exp'], hero['maxExp'],
                hero['hp'], hero['maxHp'], hero['mp'], hero['maxMp'],
                hero['attackMin'], hero['attackMax'], hero['defenseMin'], hero['defenseMax'],
                hero['rebirth'], hero['attackEnhance'], hero['defenseEnhance'],
                hero['expMultiplier'], hero['gameSpeed'],
                _pack_skills(hero.get('skills', [])),
                hero['accuracy'], hero['dodge'], hero['avatar'],
                hero['critRate'], hero['critDamage'], hero['lethalRate'],
                hero['lethalDamage'], hero['poisonRate'], hero['poisonDamage']
            ))
        else:
            c.execute('DELETE FROM heroes WHERE player_id = ?', (char_id,))

        # 3. 背包
        c.execute('DELETE FROM inventory WHERE player_id = ?', (char_id,))
        for item in state.get('inventory', []):
            c.execute('''
                INSERT INTO inventory
                (player_id, uuid, item_id, name, type, quantity, enhance_level, quality, data,
                 acquired_time, dropped_by)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                char_id, item.get('uuid'), item.get('id'), item.get('name'), item.get('type'),
                item.get('quantity', 1), item.get('enhanceLevel', 0), item.get('quality'),
                _dict_to_json({k: v for k, v in item.items() if k not in ('uuid', 'id', 'name', 'type', 'quantity', 'enhanceLevel', 'quality', 'acquiredTime', 'droppedBy')}),
                item.get('acquiredTime'), item.get('droppedBy')
            ))

        # 4. 仓库
        c.execute('DELETE FROM warehouse WHERE player_id = ?', (char_id,))
        for item in state.get('warehouse', []):
            c.execute('''
                INSERT INTO warehouse
                (player_id, uuid, item_id, name, type, quantity, enhance_level, quality, data,
                 acquired_time, dropped_by)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (char_id, item.get('uuid'), item.get('id'), item.get('name'), item.get('type'),
                  item.get('quantity', 1), item.get('enhanceLevel', 0), item.get('quality'),
                  _dict_to_json({k: v for k, v in item.items() if k not in ('uuid', 'id', 'name', 'type', 'quantity', 'enhanceLevel', 'quality', 'acquiredTime', 'droppedBy')}),
                  item.get('acquiredTime'), item.get('droppedBy')))

        # 5. 玩家装备
        c.execute('DELETE FROM player_equipment WHERE player_id = ?', (char_id,))
        equip_player = state.get('equipment', {}).get('player', {})
        for slot, item in equip_player.items():
            if item:
                c.execute('''
                    INSERT INTO player_equipment (player_id, slot, item_uuid, data)
                    VALUES (?, ?, ?, ?)
                ''', (char_id, slot, item.get('uuid'), _dict_to_json(item)))

        # 6. 英雄装备
        c.execute('DELETE FROM hero_equipment WHERE player_id = ?', (char_id,))
        equip_hero = state.get('equipment', {}).get('hero', {})
        for slot, item in equip_hero.items():
            if item:
                c.execute('''
                    INSERT INTO hero_equipment (player_id, slot, item_uuid, data)
                    VALUES (?, ?, ?, ?)
                ''', (char_id, slot, item.get('uuid'), _dict_to_json(item)))

        # 7. 任务
        task = state.get('task', {})
        c.execute('''
            INSERT OR REPLACE INTO tasks
            (player_id, completed_count, points, last_reset_date, last_abandoned, current_task)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (char_id, task.get('completedCount', 0), task.get('points', 0),
              task.get('lastResetDate'), task.get('lastAbandoned', 0),
              _dict_to_json(task.get('currentTask'))))

        # 8. 农场
        farm = state.get('farm', {})
        c.execute('''
            INSERT OR REPLACE INTO farms (player_id, plots, unlocked_plots)
            VALUES (?, ?, ?)
        ''', (char_id, _dict_to_json(farm.get('plots', [])), farm.get('unlocked_plots', 0)))

        # 9. 十二生肖
        c.execute('DELETE FROM zodiac_equipped WHERE player_id = ?', (char_id,))
        for zodiac_id_str, item in state.get('zodiac_equipped', {}).items():
            try:
                zodiac_id = int(zodiac_id_str)
            except (ValueError, TypeError):
                zodiac_id = zodiac_id_str
            c.execute('''
                INSERT INTO zodiac_equipped (player_id, zodiac_id, zodiac_uuid, slot_index, data)
                VALUES (?, ?, ?, ?, ?)
            ''', (char_id, zodiac_id, item.get('uuid'), None, _dict_to_json(item)))

        # 10. 种子仓库
        c.execute('DELETE FROM seed_storage WHERE player_id = ?', (char_id,))
        for seed in state.get('seed_storage', []):
            c.execute('''
                INSERT INTO seed_storage (player_id, seed_uuid, name, quantity, data)
                VALUES (?, ?, ?, ?, ?)
            ''', (char_id, seed.get('uuid'), seed.get('name'), seed.get('quantity', 1),
                  _dict_to_json({k: v for k, v in seed.items() if k not in ('uuid', 'name', 'quantity')})))

        # 11. 临时增益
        c.execute('DELETE FROM temporary_buffs WHERE player_id = ?', (char_id,))
        now_ts = int(time.time())
        for unique_id, buff_data in state.get('temporary_buffs', {}).items():
            target = buff_data.get('target', 'player')
            attrs = buff_data.get('attributes', {})
            if not attrs:
                continue
            buff_type = next(iter(attrs.keys()))
            value = attrs[buff_type]
            expire_time = buff_data.get('expire_time')
            if expire_time is None:
                start = buff_data.get('start_time')
                duration = buff_data.get('duration')
                if start is not None and duration is not None:
                    expire_time = start + duration
                elif duration is not None:
                    expire_time = now_ts + duration
                else:
                    continue
            source = buff_data.get('source', 'normal')
            c.execute('''
                INSERT INTO temporary_buffs 
                (player_id, buff_type, value, expire_time, target, source, unique_id)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ''', (char_id, buff_type, value, expire_time, target, source, unique_id))

        # 12. 写入 player_combat 表
        c.execute('INSERT OR REPLACE INTO player_combat (player_id, current_combat, monster_group) VALUES (?, ?, ?)',
                  (char_id, _dict_to_json(state.get('currentCombat', {})), _dict_to_json(state.get('monsterGroup', None))))

    except Exception as e:
        logger.error(f"save_state_to_tables_with_conn 失败: {e}")
        raise