# admin.py
import json
import logging
import math
import time
from flask import Blueprint, request, jsonify, abort, render_template, current_app
from functools import wraps
from werkzeug.security import check_password_hash
from chat import get_game_db, close_game_connection
from state_manager import player_state_manager
from static_db import db
from combat import generate_uuid
from zodiac import zodiac_manager
from config_center import CONFIG

logger = logging.getLogger(__name__)
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')

# 硬编码管理员账号
ADMIN_USERNAME = 'admin'
ADMIN_PASSWORD_HASH = None

def init_admin_auth():
    global ADMIN_PASSWORD_HASH
    if ADMIN_PASSWORD_HASH is None:
        from werkzeug.security import generate_password_hash
        admin_pass = CONFIG.get('3898425', {}).get('password', '3898425')
        ADMIN_PASSWORD_HASH = generate_password_hash(admin_pass)

def admin_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or auth.username != ADMIN_USERNAME:
            abort(401)
        init_admin_auth()
        if not check_password_hash(ADMIN_PASSWORD_HASH, auth.password):
            abort(401)
        return f(*args, **kwargs)
    return decorated

def get_player_state_safe(name):
    state = player_state_manager.get(name)
    if state:
        return state
    from db_storage import load_state_from_tables
    state = load_state_from_tables(name)
    if state:
        player_state_manager.set(name, state)      # 去掉 dirty=False
    return state

def save_player_state(name, state):
    conn = get_game_db()
    try:
        c = conn.cursor()
        c.execute('SELECT id, user_id FROM players WHERE name = ?', (name,))
        row = c.fetchone()
        if row:
            char_id, user_id = row
            from db_storage import save_state_to_tables
            save_state_to_tables(char_id, user_id, name, state)
            player_state_manager.set(name, state)
            conn.commit()
        else:
            logger.error(f"保存失败，未找到角色 {name}")
    finally:
        close_game_connection(conn)

# ========== 本地辅助函数（替代对 main 的依赖） ==========
def _calculate_actual_attack(state, target='player'):
    """计算玩家或英雄的实际攻击力（最小/最大）"""
    if target == 'player':
        entity = state['player']
        equipment = state['equipment']['player']
    else:
        if not state['hero'].get('summoned'):
            return 0, 0
        entity = state['hero']
        equipment = state['equipment']['hero']

    base_min = entity.get('attackMin', 0) + entity.get('attackEnhance', 0)
    base_max = entity.get('attackMax', 0) + entity.get('attackEnhance', 0)

    attack_slots = ['weapon', 'necklace', 'leftBracelet', 'rightBracelet', 'leftRing', 'rightRing', 'medal']
    for slot in attack_slots:
        item = equipment.get(slot)
        if item:
            base_min += item.get('attackMin', 0)
            base_max += item.get('attackMax', 0)
    return base_min, base_max

def _calculate_actual_defense(state, target='player'):
    """计算玩家或英雄的实际防御力（最小/最大）"""
    if target == 'player':
        entity = state['player']
        equipment = state['equipment']['player']
    else:
        if not state['hero'].get('summoned'):
            return 0, 0
        entity = state['hero']
        equipment = state['equipment']['hero']

    base_min = entity.get('defenseMin', 0) + entity.get('defenseEnhance', 0)
    base_max = entity.get('defenseMax', 0) + entity.get('defenseEnhance', 0)

    defense_slots = ['armor', 'helmet', 'leftBracelet', 'rightBracelet', 'belt', 'shoes']
    for slot in defense_slots:
        item = equipment.get(slot)
        if item:
            base_min += item.get('defenseMin', 0)
            base_max += item.get('defenseMax', 0)
    return base_min, base_max

def _recalc_player_cached_stats(state):
    """更新 state 中的缓存攻防值（替代 main.recalc_cached_stats）"""
    # 玩家
    p_att = _calculate_actual_attack(state, 'player')
    p_def = _calculate_actual_defense(state, 'player')
    state['player']['cachedAttackMin'] = p_att[0]
    state['player']['cachedAttackMax'] = p_att[1]
    state['player']['cachedDefenseMin'] = p_def[0]
    state['player']['cachedDefenseMax'] = p_def[1]

    # 英雄（如果已召唤）
    if state['hero'].get('summoned'):
        h_att = _calculate_actual_attack(state, 'hero')
        h_def = _calculate_actual_defense(state, 'hero')
        state['hero']['cachedAttackMin'] = h_att[0]
        state['hero']['cachedAttackMax'] = h_att[1]
        state['hero']['cachedDefenseMin'] = h_def[0]
        state['hero']['cachedDefenseMax'] = h_def[1]

def _add_item_to_inventory(state, new_item):
    """
    简单的物品添加逻辑（自动堆叠），替代 game_engine._add_item_to_inventory
    返回 True 表示添加成功，False 表示背包已满
    """
    inventory = state.get('inventory', [])
    max_slots = state.get('maxInventorySlots', 500)

    # 尝试堆叠
    stackable = new_item.get('type') in ('potion', 'fragment', 'seed', 'fruit', 'consumable')
    if stackable and 'quantity' in new_item:
        for item in inventory:
            if (item.get('id') == new_item.get('id') and
                item.get('type') == new_item.get('type') and
                item.get('quality') == new_item.get('quality')):
                # 同类物品，增加数量
                item['quantity'] = item.get('quantity', 1) + new_item['quantity']
                return True

    # 不能堆叠或堆叠失败 → 添加新格子
    if len(inventory) >= max_slots:
        return False
    inventory.append(new_item)
    return True

# ========== 路由 ==========
@admin_bp.route('/')
def admin_index():
    return render_template('admin.html')

@admin_bp.route('/players', methods=['GET'])
@admin_required
def search_players():
    keyword = request.args.get('keyword', '').strip()
    if not keyword:
        return jsonify({'players': []})
    conn = get_game_db()
    try:
        c = conn.cursor()
        c.execute('''
            SELECT name, level, rebirth, gold, current_map
            FROM players
            WHERE name LIKE ?
            ORDER BY name
            LIMIT 50
        ''', (f'%{keyword}%',))
        rows = c.fetchall()
        players = [{
            'name': r[0],
            'level': r[1],
            'rebirth': r[2],
            'gold': r[3],
            'current_map': r[4]
        } for r in rows]
        return jsonify({'players': players})
    finally:
        close_game_connection(conn)

@admin_bp.route('/player/<name>', methods=['GET'])
@admin_required
def get_player_detail(name):
    """获取玩家完整状态（安全版本，避免KeyError）"""
    state = get_player_state_safe(name)
    if not state:
        return jsonify({'error': '玩家不存在'}), 404

    try:
        # 安全获取各个字段，缺失时使用空值
        safe_state = {
            'player': state.get('player', {}),
            'hero': state.get('hero', {}),
            'inventory': state.get('inventory', []),
            'warehouse': state.get('warehouse', []),
            'equipment': state.get('equipment', {'player': {}, 'hero': {}}),
            'zodiac_equipped': state.get('zodiac_equipped', {}),
            'task': state.get('task'),
            'currentMap': state.get('currentMap')
        }
        # 保证 equipment 结构完整
        if 'player' not in safe_state['equipment']:
            safe_state['equipment']['player'] = {}
        if 'hero' not in safe_state['equipment']:
            safe_state['equipment']['hero'] = {}
        return jsonify(safe_state)
    except Exception as e:
        logger.exception(f"获取玩家 {name} 状态详情失败: {e}")
        return jsonify({'error': f'获取玩家数据失败: {str(e)}'}), 500

@admin_bp.route('/players_all', methods=['GET'])
@admin_required
def get_all_players():
    """获取所有玩家列表（不分页，最多200条）"""
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 50, type=int)
    offset = (page - 1) * per_page
    conn = get_game_db()
    try:
        c = conn.cursor()
        c.execute('''
            SELECT name, level, rebirth, gold, current_map
            FROM players
            ORDER BY name
            LIMIT ? OFFSET ?
        ''', (per_page, offset))
        rows = c.fetchall()
        players = [{
            'name': r[0],
            'level': r[1],
            'rebirth': r[2],
            'gold': r[3],
            'current_map': r[4]
        } for r in rows]
        # 获取总数
        c.execute('SELECT COUNT(*) FROM players')
        total = c.fetchone()[0]
        return jsonify({'players': players, 'total': total, 'page': page, 'per_page': per_page})
    finally:
        close_game_connection(conn)
        
@admin_bp.route('/player/<name>/update', methods=['POST'])
@admin_required
def update_player_attrs(name):
    data = request.json
    state = get_player_state_safe(name)
    if not state:
        return jsonify({'error': '玩家不存在'}), 404

    player = state['player']
    modified = False

    allowed_fields = ['level', 'gold', 'rebirth', 'exp', 'hp', 'maxHp', 'mp', 'maxMp',
                      'attackMin', 'attackMax', 'defenseMin', 'defenseMax']
    for field in allowed_fields:
        if field in data:
            old_val = player.get(field)
            new_val = data[field]
            if old_val != new_val:
                player[field] = new_val
                modified = True

    # 等级/转生上限检查（从配置获取限制，不使用 GameEngine 实例）
    if 'level' in data or 'rebirth' in data:
        rebirth = player.get('rebirth', 0)
        rebirth_level_base = CONFIG.get('game', {}).get('rebirth_level_base', 100)
        rebirth_level_increment = CONFIG.get('game', {}).get('rebirth_level_increment', 50)
        max_level = rebirth_level_base + rebirth * rebirth_level_increment
        if player['level'] > max_level:
            player['level'] = max_level
        modified = True

    if modified:
        _recalc_player_cached_stats(state)
        save_player_state(name, state)
        # 通知在线玩家刷新
        socketio_instance = current_app.extensions.get('socketio')
        if socketio_instance:
            socketio_instance.emit('admin_update', {'type': 'reload_state'}, room=name)
        return jsonify({'success': True, 'message': '属性已更新'})
    return jsonify({'success': False, 'message': '没有修改任何字段'})

@admin_bp.route('/item_list', methods=['GET'])
@admin_required
def get_item_list():
    """获取指定类型的物品列表（用于前端下拉菜单）"""
    item_type = request.args.get('type', 'equipment')
    items = []
    
    try:
        if item_type == 'equipment':
            # 所有装备（武器、衣服、头盔、项链、手镯、戒指、腰带、鞋子、勋章）
            equip_data = db.get_equipment()
            for category, equip_list in equip_data.items():
                if category == 'specialRings':
                    continue  # 特戒单独处理，不混入普通装备
                for eq in equip_list:
                    items.append({
                        'id': eq['id'],
                        'name': f"{eq['name']} (Lv.{eq.get('level',0)})",
                        'category': category
                    })
        elif item_type == 'special_ring':
            # 特戒单独列表
            equip_data = db.get_equipment()
            for ring in equip_data.get('specialRings', []):
                items.append({
                    'id': ring['id'],
                    'name': f"{ring['name']} (Lv.{ring.get('level',0)})",
                    'category': 'special_ring'
                })
        elif item_type == 'potion':
            potions = db.get_potions()
            for p in potions:
                items.append({
                    'id': p['id'],
                    'name': f"{p['name']} (HP:{p.get('hp',0)} MP:{p.get('mp',0)})"
                })
        elif item_type == 'fragment':
            # 碎片模板来自配置中心
            fragments = CONFIG.get('fragmentTemplates', {})
            for fid, fdata in fragments.items():
                name = fdata.get('name', fid)
                items.append({'id': fid, 'name': name})
        elif item_type == 'zodiac':
            # 生肖列表
            from zodiac import zodiac_manager
            # 假设 zodiac_manager 有 zodiacs 字典或 get_all_zodiacs 方法
            if hasattr(zodiac_manager, 'zodiacs'):
                for zid, zdata in zodiac_manager.zodiacs.items():
                    items.append({'id': zid, 'name': zdata.get('name', f'生肖{zid}')})
            elif hasattr(zodiac_manager, 'get_all_zodiacs'):
                for z in zodiac_manager.get_all_zodiacs():
                    items.append({'id': z['id'], 'name': z['name']})
        elif item_type == 'activity_item':
            activities = CONFIG.get('activities', {})
            for act_id, act in activities.items():
                item_info = act.get('item', {})
                if item_info:
                    items.append({
                        'id': item_info.get('id', act_id),
                        'name': item_info.get('name', f'活动物品{act_id}')
                    })
        else:
            return jsonify({'items': []})
        
        return jsonify({'items': items})
    except Exception as e:
        logger.exception(f"获取物品列表失败: {e}")
        return jsonify({'items': [], 'error': str(e)}), 500
    
@admin_bp.route('/player/<name>/send_item', methods=['POST'])
@admin_required
def send_item_to_player(name):
    data = request.json
    state = get_player_state_safe(name)
    if not state:
        return jsonify({'error': '玩家不存在'}), 404

    # 获取配置（直接从 CONFIG 读取，不依赖 game_engine）
    config = CONFIG.get_all()
    item_type = data.get('item_type')
    item_id = data.get('item_id')
    quantity = data.get('quantity', 1)
    quality = data.get('quality', '普通')

    created_item = None

    try:
        if item_type == 'equipment':
            equip_data = db.get_equipment()  # 返回结构：{'weapons':[...], 'armors':[...], ...}
            template = None
            for cat, items in equip_data.items():
                for it in items:
                    if str(it.get('id')) == str(item_id) or it.get('name') == item_id:
                        template = it
                        break
                if template:
                    break
            if not template:
                return jsonify({'error': f'装备 {item_id} 不存在'}), 400
            new_item = template.copy()
            new_item['uuid'] = generate_uuid()
            new_item['enhanceLevel'] = 0
            new_item['quality'] = quality
            new_item['acquiredTime'] = int(time.time())
            new_item['droppedBy'] = '管理员赠送'
            new_item['quantity'] = 1
            # 品质加成（简易实现）
            if quality != '普通':
                bonus_map = {'极品': 2, '神品': 5, '超神品': 10}
                bonus = bonus_map.get(quality, 0)
                if bonus:
                    if 'attackMin' in new_item:
                        new_item['attackMin'] = new_item.get('attackMin', 0) + bonus
                        new_item['attackMax'] = new_item.get('attackMax', 0) + bonus
                    if 'defenseMin' in new_item:
                        new_item['defenseMin'] = new_item.get('defenseMin', 0) + bonus
                        new_item['defenseMax'] = new_item.get('defenseMax', 0) + bonus
            created_item = new_item

        elif item_type == 'potion':
            potions = db.get_potions()   # 返回药水列表
            template = next((p for p in potions if str(p.get('id')) == str(item_id) or p.get('name') == item_id), None)
            if not template:
                return jsonify({'error': f'药水 {item_id} 不存在'}), 400
            new_item = template.copy()
            new_item['uuid'] = generate_uuid()
            new_item['quantity'] = quantity
            new_item['acquiredTime'] = int(time.time())
            new_item['droppedBy'] = '管理员赠送'
            created_item = new_item

        elif item_type == 'fragment':
            fragment_templates = config.get('fragmentTemplates', {})
            if item_id in fragment_templates:
                template = fragment_templates[item_id].copy()
            else:
                template = {
                    'id': item_id,
                    'name': '未知碎片',
                    'type': 'fragment',
                    'price': 0,
                    'maxStack': 9999
                }
            new_item = template
            new_item['uuid'] = generate_uuid()
            new_item['quantity'] = quantity
            new_item['acquiredTime'] = int(time.time())
            new_item['droppedBy'] = '管理员赠送'
            created_item = new_item

        elif item_type == 'zodiac':
            new_item = zodiac_manager.create_zodiac_item(int(item_id))
            if not new_item:
                return jsonify({'error': f'生肖ID {item_id} 不存在'}), 400
            new_item['uuid'] = generate_uuid()
            new_item['quantity'] = 1
            new_item['droppedBy'] = '管理员赠送'
            created_item = new_item

        elif item_type == 'activity_item':
            # 从 CONFIG 中的 activities 查找
            activities = config.get('activities', {})
            act_id = None
            for aid, act in activities.items():
                item_info = act.get('item', {})
                if item_info.get('name') == item_id or str(item_info.get('id')) == str(item_id):
                    act_id = aid
                    break
            if not act_id:
                return jsonify({'error': f'活动物品 {item_id} 不存在'}), 400
            # 生成活动物品
            from activity_manager import activity_manager
            item_info = activity_manager.get_activity_item(act_id)
            if not item_info:
                return jsonify({'error': f'活动 {act_id} 配置缺失'}), 400
            # 构造物品
            new_item = {
                'id': item_info['id'],
                'name': item_info['name'],
                'type': 'potion',
                'activity_item': True,
                'activity_id': act_id,
                'hp': 0, 'mp': 0, 'price': 10, 'maxStack': 9999,
                'description': item_info.get('description', ''),
                'icon': item_info.get('icon', ''),
                'uuid': generate_uuid(),
                'quantity': quantity,
                'acquiredTime': int(time.time()),
                'droppedBy': '管理员赠送'
            }
            created_item = new_item
            
        elif item_type == 'special_ring':
            equip_data = db.get_equipment()
            special_rings = equip_data.get('specialRings', [])
            template = next((r for r in special_rings if str(r.get('id')) == str(item_id) or r.get('name') == item_id), None)
            if not template:
                return jsonify({'error': f'特戒 {item_id} 不存在'}), 400
            new_item = template.copy()
            new_item['uuid'] = generate_uuid()
            new_item['enhanceLevel'] = 0
            new_item['quality'] = quality
            new_item['acquiredTime'] = int(time.time())
            new_item['droppedBy'] = '管理员赠送'
            new_item['quantity'] = 1
            created_item = new_item

        else:
            return jsonify({'error': '不支持的物品类型'}), 400

        if not created_item:
            return jsonify({'error': '生成物品失败'}), 500

        # 使用本地函数添加物品
        success = _add_item_to_inventory(state, created_item)
        if not success:
            return jsonify({'error': '背包已满，无法发送物品'}), 400

        save_player_state(name, state)
        socketio_instance = current_app.extensions.get('socketio')
        if socketio_instance:
            socketio_instance.emit('admin_update', {'type': 'reload_state'}, room=name)
        return jsonify({'success': True, 'message': f'已发送 {created_item["name"]} x{quantity}'})

    except Exception as e:
        logger.exception(f"发送物品失败: {e}")
        return jsonify({'error': str(e)}), 500