"""
日报生成核心逻辑
"""
import os
import json
from datetime import datetime, timedelta
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill
import pytz

from lib.db import execute_query, execute_insert, execute_update
from lib.field_mapping import get_field_display_name, get_finish_reason
from lib.logger import log_info, log_error, log_warning


# ID字段到名称的映射配置
# key: 订单表中的ID字段名
# value: (关联表名, 关联表ID字段, 关联表名称字段)
ID_TO_NAME_MAPPING = {
    'user_id': ('t_user', 'id', 'user_name'),
    'company_id': ('t_company', 'id', 'company_name'),
    'station_id': ('t_station', 'id', 'station_name'),
    'equipment_id': ('t_equipment', 'id', 'equipment_name'),
    'connector_id': ('t_connector', 'id', 'connector_name'),
}


# 特来电表字段映射到报表字段
# t_hlht_tld 字段 → 报表字段
TELECOM_FIELD_MAPPING = {
    'order_id': 'order_no',           # 订单号
    'station_id': 'station_id',       # 场站ID
    'operator_name': 'station_name',  # 运营商名称 → 场站名称
    'connector_name': 'equipment_name',  # 连接器名称 → 设备名称
    'charge_start_time': 'charge_begin_time',  # 开始充电时间
    'charge_end_time': 'charge_end_time',      # 结束充电时间
    'total_power': 'charge_degree',   # 总电量
    'start_soc': 'charge_begin_soc',  # 开始SOC
    'end_soc': 'charge_end_soc',      # 结束SOC
    'elec_money': 'charge_elecfee_amount',  # 电费
    'service_money': 'charge_service_amount',  # 服务费
    'total_money': 'total_money',     # 总金额
    'sharp_power': 'sharp_electricity',  # 尖时段电量
    'peak_power': 'peak_electricity',    # 峰时段电量
    'flat_power': 'flat_electricity',    # 平时段电量
    'valley_power': 'valley_electricity',  # 谷时段电量
    'vehicle_self_no': 'company_name',   # 车量自编号 → 企业名称
    'plate_no': 'charge_plate_no',       # 车牌号
    'vin_code': 'charge_vin',            # VIN码
    'stop_reason': 'finish_msg',         # 结束原因
    'charge_duration_sec': 'charge_duration',  # 充电时长(秒)
}

# 特来电数据中名称字段到ID字段的映射（用于匹配selected_fields中的ID字段）
TELECOM_NAME_TO_ID_FIELDS = {
    'company_name': 'company_id',
    'station_name': 'station_id',
    'equipment_name': 'equipment_id',
}


def query_telecom_orders(vehicle_self_nos, start_time_str, end_time_str):
    """
    查询特来电平台的订单数据
    
    Args:
        vehicle_self_nos: 车量自编号列表（对应企业名称）
        start_time_str: 开始时间字符串
        end_time_str: 结束时间字符串
    
    Returns:
        list: 转换后的订单数据，字段映射为报表字段
    """
    if not vehicle_self_nos:
        return []
    
    # 构建查询条件
    placeholders = ', '.join(['%s'] * len(vehicle_self_nos))
    sql = f"""
        SELECT 
            order_id,
            station_id,
            operator_name,
            connector_name,
            charge_start_time,
            charge_end_time,
            charge_duration_sec,
            total_power,
            start_soc,
            end_soc,
            elec_money,
            service_money,
            total_money,
            sharp_power,
            peak_power,
            flat_power,
            valley_power,
            vehicle_self_no,
            plate_no,
            vin_code,
            stop_reason
        FROM t_hlht_tld
        WHERE vehicle_self_no IN ({placeholders})
        AND second_source != '驿来特'
        AND charge_end_time >= %s
        AND charge_end_time < %s
        ORDER BY charge_end_time DESC
    """
    
    params = tuple(vehicle_self_nos) + (start_time_str, end_time_str)
    
    try:
        results = execute_query(sql, params)
        log_info(f"[特来电] 查询到 {len(results)} 条订单", 'report')
    except Exception as e:
        log_error(f"[特来电] 查询失败: {e}", 'report')
        return []
    
    # 转换字段名
    converted_orders = []
    for row in results:
        converted = {}
        for telecom_field, report_field in TELECOM_FIELD_MAPPING.items():
            if telecom_field in row:
                converted[report_field] = row[telecom_field]
        
        # 将名称字段复制到对应的ID字段，以便ID转名称逻辑能正确处理
        # 例如：company_name → company_id（值相同），这样 build_id_to_name_map 会查询 t_company 表
        # 但由于值是名称而不是ID，查询会失败，所以我们需要特殊处理
        for name_field, id_field in TELECOM_NAME_TO_ID_FIELDS.items():
            if name_field in converted:
                converted[id_field] = converted[name_field]
        
        # 添加数据来源标记
        converted['data_source'] = '特来电'
        converted_orders.append(converted)
    
    return converted_orders


def build_id_to_name_map(orders, selected_fields):
    """
    构建ID到名称的映射字典
    
    Args:
        orders: 订单数据列表
        selected_fields: 选中的字段列表
    
    Returns:
        dict: {field_name: {id_value: name_value}}
    """
    id_name_maps = {}
    
    for field in selected_fields:
        if field not in ID_TO_NAME_MAPPING:
            continue
        
        table_name, id_field, name_field = ID_TO_NAME_MAPPING[field]
        
        # 收集所有需要查询的ID值
        id_values = set()
        telecom_name_values = {}  # 特来电数据中的名称值（直接使用）
        
        for order in orders:
            val = order.get(field)
            if val is not None and val != '' and val != 0:
                # 检查是否是特来电订单
                if order.get('data_source') == '特来电' and field in TELECOM_NAME_TO_ID_FIELDS.values():
                    # 特来电数据中的ID字段实际是名称，直接使用
                    telecom_name_values[str(val)] = str(val)
                else:
                    id_values.add(str(val))
        
        # 合并特来电的名称映射
        if telecom_name_values:
            id_name_maps[field] = telecom_name_values
            log_info(f"[ID转换] {field}: 特来电数据直接使用名称 {len(telecom_name_values)} 个", 'report')
        
        # 查询驿来特数据的ID映射
        if not id_values:
            continue
        
        # 批量查询名称
        placeholders = ', '.join(['%s'] * len(id_values))
        sql = f"SELECT {id_field} AS id_val, {name_field} AS name_val FROM {table_name} WHERE {id_field} IN ({placeholders})"
        
        try:
            results = execute_query(sql, tuple(id_values))
            if field not in id_name_maps:
                id_name_maps[field] = {}
            id_name_maps[field].update({str(row['id_val']): row['name_val'] for row in results})
            log_info(f"[ID转换] {field}: 查询到 {len(results)} 个名称映射", 'report')
        except Exception as e:
            log_error(f"[ID转换] {field} 查询失败: {e}", 'report')
            if field not in id_name_maps:
                id_name_maps[field] = {}
    
    return id_name_maps


def calculate_time_period_electricity(orders, time_periods_config):
    """
    计算分时段电量
    
    从 t_equipment_charge_order_detail 表查询分时电量数据，
    根据时段配置计算各时段的电量总和。
    
    Args:
        orders: 订单数据列表
        time_periods_config: 时段配置 {sharp: [11,12], peak: [9,10], flat: [7,8], valley: [0,1,2,3]}
    
    Returns:
        dict: {order_no: {sharp_electricity: x, peak_electricity: y, flat_electricity: z, valley_electricity: w}}
    """
    if not time_periods_config or not any(time_periods_config.values()):
        return {}
    
    # 收集所有订单号
    order_nos = [order.get('order_no') for order in orders if order.get('order_no')]
    if not order_nos:
        return {}
    
    # 构建小时到时段的映射
    hour_to_period = {}
    for period_key, hours in time_periods_config.items():
        for hour in hours:
            hour_to_period[hour] = period_key
    
    if not hour_to_period:
        return {}
    
    # 批量查询订单的分时电量
    placeholders = ', '.join(['%s'] * len(order_nos))
    sql = f"""
        SELECT order_no, charge_degree, charge_startr_time, time_flag
        FROM t_equipment_charge_order_detail
        WHERE order_no IN ({placeholders})
        ORDER BY order_no, charge_startr_time
    """
    
    try:
        details = execute_query(sql, tuple(order_nos))
        log_info(f"[时段电量] 查询到 {len(details)} 条分时记录", 'report')
    except Exception as e:
        log_error(f"[时段电量] 查询失败: {e}", 'report')
        return {}
    
    # 按订单号分组计算各时段电量
    result = {}
    for order_no in order_nos:
        result[order_no] = {
            'sharp_electricity': 0.0,
            'peak_electricity': 0.0,
            'flat_electricity': 0.0,
            'valley_electricity': 0.0
        }
    
    for detail in details:
        order_no = detail.get('order_no')
        if order_no not in result:
            continue
        
        charge_degree = float(detail.get('charge_degree', 0) or 0)
        charge_start_time = detail.get('charge_startr_time')
        
        if not charge_start_time:
            continue
        
        # 获取小时数
        if isinstance(charge_start_time, datetime):
            hour = charge_start_time.hour
        elif isinstance(charge_start_time, str):
            try:
                hour = datetime.strptime(str(charge_start_time), '%Y-%m-%d %H:%M:%S').hour
            except:
                continue
        else:
            continue
        
        # 根据小时确定时段
        period_key = hour_to_period.get(hour)
        if period_key and f'{period_key}_electricity' in result[order_no]:
            result[order_no][f'{period_key}_electricity'] += charge_degree
    
    return result


def balance_time_period_electricity(orders):
    """
    找平分时段电量
    
    正常情况下：充电电量(charge_degree) = 尖电量 + 峰电量 + 平电量 + 谷电量
    但平台导出数据时，四者之和可能不等于充电电量。
    本函数以充电电量(charge_degree)为准，将差额加到对应时段上。
    
    找平原则（按优先级顺序）：
    1. 有谷电量(>0) → 差额加到谷上
    2. 没谷有平电量(>0) → 差额加到平上
    3. 没平有峰电量(>0) → 差额加到峰上
    4. 都没有 → 差额加到尖上
    
    Args:
        orders: 订单数据列表（会原地修改 sharp/peak/flat/valley_electricity 字段）
    
    Returns:
        int: 实际找平的订单数
    """
    balanced_count = 0
    
    for order in orders:
        # 获取充电电量（作为基准）
        charge_degree = order.get('charge_degree')
        if charge_degree is None or charge_degree == '':
            continue
        
        try:
            charge_degree = float(charge_degree)
        except (ValueError, TypeError):
            continue
        
        # 获取各时段电量
        sharp = float(order.get('sharp_electricity', 0) or 0)
        peak = float(order.get('peak_electricity', 0) or 0)
        flat = float(order.get('flat_electricity', 0) or 0)
        valley = float(order.get('valley_electricity', 0) or 0)
        
        # 计算四时段之和
        period_sum = round(sharp + peak + flat + valley, 3)
        
        # 计算差额
        diff = round(charge_degree - period_sum, 3)
        
        # 如果差额为0，不需要找平
        if abs(diff) < 0.001:
            continue
        
        # 按优先级找平：谷 → 平 → 峰 → 尖
        if valley > 0:
            order['valley_electricity'] = round(valley + diff, 3)
        elif flat > 0:
            order['flat_electricity'] = round(flat + diff, 3)
        elif peak > 0:
            order['peak_electricity'] = round(peak + diff, 3)
        else:
            order['sharp_electricity'] = round(sharp + diff, 3)
        
        balanced_count += 1
    
    return balanced_count


def get_beijing_time():
    """获取北京时间"""
    beijing_tz = pytz.timezone('Asia/Shanghai')
    return datetime.now(beijing_tz)


def generate_daily_report(config_id, start_time=None, end_time=None):
    """
    生成日报
    
    Args:
        config_id: 配置ID
        start_time: 开始时间（可选，默认为昨天8点）
        end_time: 结束时间（可选，默认为今天8点）
    
    Returns:
        dict: 生成结果，包含 success, message, file_path, total_orders, total_amount, sum_results
    """
    try:
        # 获取配置信息
        configs = execute_query(
            'SELECT * FROM t_daily_report_config WHERE id = %s',
            (config_id,)
        )
        
        if not configs:
            return {'success': False, 'message': '配置不存在'}
        
        config = configs[0]
        
        # 解析字段
        selected_fields = json.loads(config['selected_fields'])
        sum_fields = json.loads(config['sum_fields']) if config['sum_fields'] else []
        
        # 根据配置自动添加虚拟字段到选中字段列表
        show_custom_service_fee = config.get('show_custom_service_fee', 0) == 1
        show_total_amount = config.get('show_total_amount', 0) == 1
        
        if show_custom_service_fee and 'custom_service_fee' not in selected_fields:
            selected_fields.append('custom_service_fee')
        
        if show_total_amount and 'custom_total_amount' not in selected_fields:
            selected_fields.append('custom_total_amount')
        
        # 设置时间范围
        if not start_time or not end_time:
            now = get_beijing_time()
            end_time = now.replace(hour=8, minute=0, second=0, microsecond=0)
            start_time = end_time - timedelta(days=1)
        
        # 格式化时间
        start_time_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
        end_time_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
        
        log_info(f"[日报生成] 开始生成日报", 'report')
        log_info(f"  配置ID: {config_id}", 'report')
        log_info(f"  配置名称: {config['config_name']}", 'report')
        log_info(f"  拆分方式: {config['split_type']} = {config['split_value']}", 'report')
        log_info(f"  时间范围: {start_time_str} 至 {end_time_str}", 'report')
        log_info(f"  选择字段: {len(selected_fields)} 个", 'report')
        
        # 删除同一配置、同一日期、同一拆分的旧数据（覆盖）
        report_date = start_time.strftime('%Y-%m-%d')
        delete_old_history(config_id, report_date, config['split_type'], config['split_value'])
        
        # 构建查询SQL - 过滤掉虚拟字段（时段电量、自定义服务费、自定义实收总金额、车辆信息、充电卡信息等）
        # 虚拟字段不是数据库表中的实际字段，需要动态计算或关联查询
        # 注意：total_amount 是旧版虚拟字段名，为了向后兼容也需要包含在内
        VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'custom_total_amount', 'total_amount', 'car_bus_path', 'car_sn', 'user_card_memo'}
        db_fields = [f for f in selected_fields if f not in VIRTUAL_FIELDS]
        
        # 确保 charge_degree 总是被查询（用于计算总电量）
        if 'charge_degree' not in db_fields:
            db_fields.append('charge_degree')
        
        # 如果选择了自定义实收总金额字段，需要确保查询 charge_elecfee_amount（电费金额）
        if 'custom_total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
            db_fields.append('charge_elecfee_amount')
        
        # 确保至少有 order_no 字段用于关联分时数据
        if 'order_no' not in db_fields:
            db_fields.append('order_no')
        
        # 如果选择了车辆信息字段，需要确保查询 charge_vin（用于关联 t_car 表）
        need_car_info = 'car_bus_path' in selected_fields or 'car_sn' in selected_fields
        if need_car_info and 'charge_vin' not in db_fields:
            db_fields.append('charge_vin')
        
        # 如果选择了充电卡备注字段，需要确保查询 user_card_no（用于关联 t_user_card 表）
        need_card_memo = 'user_card_memo' in selected_fields
        if need_card_memo and 'user_card_no' not in db_fields:
            db_fields.append('user_card_no')
        
        fields_str = ', '.join(db_fields)
        
        # 检查是否为多选值（逗号分隔）
        split_values = [v.strip() for v in config['split_value'].split(',') if v.strip()]
        
        if len(split_values) > 1:
            # 多选：使用 IN 查询
            placeholders = ', '.join(['%s'] * len(split_values))
            sql = f"""
                SELECT {fields_str}
                FROM t_equipment_charge_order
                WHERE state = 3
                AND report_time >= %s
                AND report_time < %s
                AND {config['split_type']} IN ({placeholders})
                ORDER BY report_time DESC
            """
            params = [start_time_str, end_time_str] + split_values
        else:
            # 单选：使用 = 查询
            sql = f"""
                SELECT {fields_str}
                FROM t_equipment_charge_order
                WHERE state = 3
                AND report_time >= %s
                AND report_time < %s
                AND {config['split_type']} = %s
                ORDER BY report_time DESC
            """
            params = [start_time_str, end_time_str, config['split_value']]
        
        # 执行查询
        orders = execute_query(sql, tuple(params))
        # 转换为列表，方便后续添加特来电数据
        orders = list(orders) if orders else []
        
        log_info(f"[日报生成] 驿来特查询到 {len(orders)} 条订单", 'report')
        
        # 添加数据来源标记并转换结束原因
        for order in orders:
            order['data_source'] = '驿来特'
            # 转换结束原因
            finish_type = order.get('finish_type')
            finish_code = order.get('finish_code')
            finish_msg = order.get('finish_msg')
            if finish_type is not None:
                order['finish_msg'] = get_finish_reason(finish_type, finish_code, finish_msg)
        
        # 如果需要车辆信息，从 t_car 表关联查询
        if need_car_info and orders:
            # 获取所有 VIN 码
            vin_list = list(set(order.get('charge_vin') for order in orders if order.get('charge_vin')))
            if vin_list:
                placeholders = ', '.join(['%s'] * len(vin_list))
                car_sql = f"""
                    SELECT car_vin, car_bus_path, car_sn 
                    FROM t_car 
                    WHERE car_vin IN ({placeholders})
                """
                car_results = execute_query(car_sql, tuple(vin_list))
                car_map = {car['car_vin']: car for car in car_results}
                
                # 将车辆信息添加到订单中
                for order in orders:
                    vin = order.get('charge_vin')
                    if vin and vin in car_map:
                        car_info = car_map[vin]
                        order['car_bus_path'] = car_info.get('car_bus_path', '')
                        order['car_sn'] = car_info.get('car_sn', '')
                    else:
                        order['car_bus_path'] = ''
                        order['car_sn'] = ''
                log_info(f"[日报生成] 关联查询到 {len(car_map)} 条车辆信息", 'report')
        
        # 如果需要充电卡信息，从 t_user_card 表关联查询
        if need_card_memo and orders:
            # 获取所有充电卡号
            card_no_list = list(set(order.get('user_card_no') for order in orders if order.get('user_card_no')))
            if card_no_list:
                placeholders = ', '.join(['%s'] * len(card_no_list))
                card_sql = f"""
                    SELECT card_no, memo 
                    FROM t_user_card 
                    WHERE card_no IN ({placeholders})
                """
                card_results = execute_query(card_sql, tuple(card_no_list))
                card_map = {card['card_no']: card for card in card_results}
                
                # 将充电卡备注添加到订单中
                for order in orders:
                    card_no = order.get('user_card_no')
                    if card_no and card_no in card_map:
                        card_info = card_map[card_no]
                        order['user_card_memo'] = card_info.get('memo', '')
                    else:
                        order['user_card_memo'] = ''
                log_info(f"[日报生成] 关联查询到 {len(card_map)} 条充电卡信息", 'report')
        
        # 检查是否有补单记录（finish_type = 2 表示补单结束）
        has_supplement = any(order.get('finish_type') == 2 for order in orders)
        if has_supplement:
            log_info(f"[日报生成] 检测到补单记录，将在文件名中添加标记", 'report')
        
        # 检查是否需要合并特来电数据
        merge_telecom = config.get('merge_telecom') or 0
        telecom_vehicle_no = config.get('telecom_vehicle_no') or ''
        
        log_info(f"[日报生成] 特来电合并配置: merge_telecom={merge_telecom}, split_type={config['split_type']}, vehicle_no={telecom_vehicle_no}", 'report')
        
        if merge_telecom and config['split_type'] == 'company_id' and telecom_vehicle_no:
            # 解析车量自编号（支持逗号分隔的多个）
            vehicle_nos = [v.strip() for v in telecom_vehicle_no.split(',') if v.strip()]
            if vehicle_nos:
                log_info(f"[日报生成] 开始合并特来电数据，车量自编号: {vehicle_nos}", 'report')
                telecom_orders = query_telecom_orders(vehicle_nos, start_time_str, end_time_str)
                log_info(f"[日报生成] 特来电查询到 {len(telecom_orders)} 条订单", 'report')
                if telecom_orders:
                    # 将特来电数据添加到订单列表
                    orders.extend(telecom_orders)
                    log_info(f"[日报生成] 合并后总订单数: {len(orders)}", 'report')
                    # 检查特来电数据中是否有补单记录
                    if not has_supplement:
                        has_supplement = any(order.get('finish_type') == 2 for order in telecom_orders)
                    
                    # 合并后再次处理车辆信息（针对特来电订单）
                    if need_car_info:
                        telecom_vin_list = list(set(order.get('charge_vin') for order in telecom_orders if order.get('charge_vin')))
                        if telecom_vin_list:
                            placeholders = ', '.join(['%s'] * len(telecom_vin_list))
                            car_sql = f"""
                                SELECT car_vin, car_bus_path, car_sn 
                                FROM t_car 
                                WHERE car_vin IN ({placeholders})
                            """
                            car_results = execute_query(car_sql, tuple(telecom_vin_list))
                            car_map = {car['car_vin']: car for car in car_results}
                            
                            for order in telecom_orders:
                                vin = order.get('charge_vin')
                                if vin and vin in car_map:
                                    car_info = car_map[vin]
                                    order['car_bus_path'] = car_info.get('car_bus_path', '')
                                    order['car_sn'] = car_info.get('car_sn', '')
                                else:
                                    order['car_bus_path'] = ''
                                    order['car_sn'] = ''
                            log_info(f"[日报生成] 特来电数据关联查询到 {len(car_map)} 条车辆信息", 'report')
                    
                    # 合并后再次处理充电卡信息（针对特来电订单）
                    if need_card_memo:
                        telecom_card_no_list = list(set(order.get('user_card_no') for order in telecom_orders if order.get('user_card_no')))
                        if telecom_card_no_list:
                            placeholders = ', '.join(['%s'] * len(telecom_card_no_list))
                            card_sql = f"""
                                SELECT card_no, memo 
                                FROM t_user_card 
                                WHERE card_no IN ({placeholders})
                            """
                            card_results = execute_query(card_sql, tuple(telecom_card_no_list))
                            card_map = {card['card_no']: card for card in card_results}
                            
                            for order in telecom_orders:
                                card_no = order.get('user_card_no')
                                if card_no and card_no in card_map:
                                    card_info = card_map[card_no]
                                    order['user_card_memo'] = card_info.get('memo', '')
                                else:
                                    order['user_card_memo'] = ''
                            log_info(f"[日报生成] 特来电数据关联查询到 {len(card_map)} 条充电卡信息", 'report')
        
        if not orders:
            # 即使没有数据，也保存一条失败记录
            save_report_history(
                report_date=start_time.strftime('%Y-%m-%d'),
                start_time=start_time_str,
                end_time=end_time_str,
                split_type=config['split_type'],
                split_value=config['split_value'],
                split_name=config.get('split_name', config['split_value']),
                config_id=config_id,
                config_name=config.get('config_name', ''),
                total_orders=0,
                total_amount=0,
                sum_results={},
                file_path='',
                status=0
            )
            return {
                'success': False,
                'message': f'时间范围内没有符合条件的订单数据（查询条件：{start_time_str} 至 {end_time_str}，{config["split_type"]}={config["split_value"]}，state=3）'
            }
        
        # 解析时段配置并计算分时段电量
        time_periods_config = json.loads(config['time_periods']) if config.get('time_periods') else {}
        if time_periods_config and any(time_periods_config.values()):
            log_info(f"[日报生成] 时段配置: {time_periods_config}", 'report')
            time_period_electricity = calculate_time_period_electricity(orders, time_periods_config)
            
            # 将分时段电量添加到订单数据中（仅对驿来特订单，特来电订单已有数据）
            for order in orders:
                # 特来电订单已有尖峰平谷电量数据，不需要重新计算
                if order.get('data_source') == '特来电':
                    continue
                    
                order_no = order.get('order_no')
                if order_no and order_no in time_period_electricity:
                    ep = time_period_electricity[order_no]
                    order['sharp_electricity'] = ep['sharp_electricity']
                    order['peak_electricity'] = ep['peak_electricity']
                    order['flat_electricity'] = ep['flat_electricity']
                    order['valley_electricity'] = ep['valley_electricity']
            
            log_info(f"[日报生成] 已计算 {len(time_period_electricity)} 条订单的分时段电量", 'report')
        
        # 找平分时段电量
        # 当配置开启了找平电量功能时，以充电电量(charge_degree)为准，
        # 将尖+峰+平+谷之和与充电电量的差额，按 谷→平→峰→尖 的优先级加到对应时段上
        balance_electricity_enabled = config.get('balance_electricity')
        # 兼容历史配置：NULL 或未设置时默认开启
        if balance_electricity_enabled is None:
            balance_electricity_enabled = 1
        
        if balance_electricity_enabled == 1:
            balanced_count = balance_time_period_electricity(orders)
            if balanced_count > 0:
                log_info(f"[日报生成] 找平电量：共处理 {balanced_count} 条订单的分时段电量差额", 'report')
        
        # 计算虚拟字段（自定义服务费、自定义实收总金额）并添加到订单数据中
        # 这样求和数据才能正确计算这些字段的总和
        has_custom_service_fee = config.get('custom_service_fee_price') is not None and str(config.get('custom_service_fee_price', '')).strip() != ''
        if has_custom_service_fee:
            custom_service_fee_price = float(config['custom_service_fee_price'])
            for order in orders:
                charge_degree = float(order.get('charge_degree', 0) or 0)
                custom_service_fee = round(charge_degree * custom_service_fee_price, 2)
                order['custom_service_fee'] = custom_service_fee
                
                # 计算自定义实收总金额（实收电费 + 自定义服务费）
                actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
                custom_total_amount = round(actual_money + custom_service_fee, 2)
                order['custom_total_amount'] = custom_total_amount
                # 兼容旧版字段名 total_amount
                order['total_amount'] = custom_total_amount
        else:
            # 如果没有自定义服务费，自定义实收总金额 = 实收电费
            for order in orders:
                actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
                custom_total_amount = round(actual_money, 2)
                order['custom_total_amount'] = custom_total_amount
                # 兼容旧版字段名 total_amount
                order['total_amount'] = custom_total_amount
        
        # 计算求和（保留三位小数）
        sum_results = {}
        for field in sum_fields:
            # 检查是否至少有一条订单包含该字段
            has_field = any(field in order for order in orders)
            if has_field:
                total = sum(float(order.get(field, 0) or 0) for order in orders)
                sum_results[field] = round(total, 3)
        
        # 强制采集充电电量（charge_degree），即使不在求和字段配置中也要采集
        if 'charge_degree' not in sum_results and orders:
            has_charge_degree = any('charge_degree' in order for order in orders)
            if has_charge_degree:
                total_charge_degree = sum(float(order.get('charge_degree', 0) or 0) for order in orders)
                sum_results['charge_degree'] = round(total_charge_degree, 3)
                log_info(f"[日报生成] 强制采集充电电量: {sum_results['charge_degree']} kWh", 'report')
        
        # 强制采集实收电费（charge_elecfee_amount），用于计算自定义实收总金额的求和
        if 'charge_elecfee_amount' not in sum_results and orders:
            has_charge_elecfee_amount = any('charge_elecfee_amount' in order for order in orders)
            if has_charge_elecfee_amount:
                total_charge_elecfee_amount = sum(float(order.get('charge_elecfee_amount', 0) or 0) for order in orders)
                sum_results['charge_elecfee_amount'] = round(total_charge_elecfee_amount, 3)
        
        # 强制采集自定义服务费（custom_service_fee），直接使用订单中已计算好的值求和
        if 'custom_service_fee' not in sum_results and orders:
            has_custom_service_fee_field = any('custom_service_fee' in order for order in orders)
            if has_custom_service_fee_field:
                total_custom_service_fee = sum(float(order.get('custom_service_fee', 0) or 0) for order in orders)
                sum_results['custom_service_fee'] = round(total_custom_service_fee, 2)
        
        # 强制采集自定义实收总金额（custom_total_amount），直接使用订单中已计算好的值求和
        if 'custom_total_amount' not in sum_results and orders:
            has_custom_total_amount = any('custom_total_amount' in order for order in orders)
            if has_custom_total_amount:
                total_custom_total_amount = sum(float(order.get('custom_total_amount', 0) or 0) for order in orders)
                sum_results['custom_total_amount'] = round(total_custom_total_amount, 2)
        
        # 构建ID到名称的映射
        id_name_maps = build_id_to_name_map(orders, selected_fields)
        
        # 生成Excel文件
        file_path = generate_excel(
            orders=orders,
            selected_fields=selected_fields,
            sum_fields=sum_fields,
            sum_results=sum_results,
            config_name=config['config_name'],
            split_name=config.get('split_name', config['split_value']),
            start_time=start_time_str,
            end_time=end_time_str,
            id_name_maps=id_name_maps,
            field_custom_names=config.get('field_custom_names'),
            has_supplement=has_supplement,
            show_monthly_total=config.get('show_monthly_total', 0) == 1,
            config_id=config['id'],
            report_date=start_time.strftime('%Y-%m-%d'),
            sort_order=config.get('sort_order'),
            split_type=config.get('split_type'),
            split_value=config.get('split_value'),
            custom_service_fee_price=config.get('custom_service_fee_price'),
            custom_service_fee_name=config.get('custom_service_fee_name'),
            show_custom_service_fee=config.get('show_custom_service_fee', 0) == 1,
            show_total_amount=config.get('show_total_amount', 0) == 1,
            total_amount_name=config.get('total_amount_name')
        )
        
        log_info(f"[日报生成] Excel文件已生成: {file_path}", 'report')
        
        # 计算总电量（包括驿来特和特来电所有订单）
        total_degree = sum(float(order.get('charge_degree', 0) or 0) for order in orders)
        
        # 保存历史记录
        log_info(f"[日报生成] 准备保存历史记录，file_path={file_path}", 'report')
        history_id = save_report_history(
            report_date=start_time.strftime('%Y-%m-%d'),
            start_time=start_time_str,
            end_time=end_time_str,
            split_type=config['split_type'],
            split_value=config['split_value'],
            split_name=config.get('split_name', config['split_value']),
            config_id=config_id,
            config_name=config.get('config_name', ''),
            total_orders=len(orders),
            total_amount=total_degree,
            sum_results=sum_results,
            file_path=file_path,
            status=1
        )
        log_info(f"[日报生成] 历史记录已保存，ID={history_id}", 'report')
        
        # 自动采集求和数据到求和数据表
        try:
            if sum_results:
                from lib.sum_data_collector import collect_sum_data_from_history
                collect_result = collect_sum_data_from_history(history_id)
                if collect_result['success']:
                    log_info(f"[日报生成] 求和数据采集成功", 'report')
                else:
                    log_warning(f"[日报生成] 求和数据采集失败: {collect_result['message']}", 'report')
        except Exception as collect_error:
            log_error(f"[日报生成] 求和数据采集异常: {str(collect_error)}", 'report')
        
        log_info(f"[日报生成] ✓ 生成成功", 'report')
        log_info(f"  订单数量: {len(orders)}", 'report')
        log_info(f"  总电量: {total_degree} kWh", 'report')
        log_info(f"  文件路径: {file_path}", 'report')
        log_info(f"  历史记录ID: {history_id}", 'report')
        
        return {
            'success': True,
            'message': '日报生成成功',
            'file_path': file_path,
            'total_orders': len(orders),
            'total_degree': total_degree,
            'sum_results': sum_results,
            'history_id': history_id
        }
        
    except Exception as e:
        log_error(f"[日报生成] ✗ 生成失败: {str(e)}", 'report')
        
        # 保存失败记录
        try:
            save_report_history(
                report_date=start_time.strftime('%Y-%m-%d') if start_time else datetime.now().strftime('%Y-%m-%d'),
                start_time=start_time_str if 'start_time_str' in locals() else '',
                end_time=end_time_str if 'end_time_str' in locals() else '',
                split_type=config['split_type'] if 'config' in locals() and config else '',
                split_value=config['split_value'] if 'config' in locals() and config else '',
                split_name=config.get('split_name', '') if 'config' in locals() and config else '',
                config_id=config_id,
                config_name=config.get('config_name', '') if 'config' in locals() and config else '',
                total_orders=0,
                total_amount=0,
                sum_results={},
                file_path='',
                status=0
            )
            log_info(f"[日报生成] 已保存失败记录到历史表", 'report')
        except Exception as save_error:
            log_error(f"[日报生成] 保存失败记录时出错: {str(save_error)}", 'report')
        
        return {
            'success': False,
            'message': f'生成日报失败: {str(e)}'
        }


def generate_excel(orders, selected_fields, sum_fields, sum_results, 
                   config_name, split_name, start_time, end_time,
                   id_name_maps=None, field_custom_names=None, has_supplement=False,
                   show_monthly_total=False, config_id=None, report_date=None, sort_order=None,
                   split_type=None, split_value=None,
                   custom_service_fee_price=None, custom_service_fee_name=None,
                   show_custom_service_fee=False, show_total_amount=False, total_amount_name=None):
    """
    生成Excel文件
    
    Args:
        id_name_maps: ID到名称的映射字典，格式为 {field_name: {id_value: name_value}}
        field_custom_names: 字段自定义名头字典，格式为 {field_key: custom_name}
        has_supplement: 是否有补单记录
        show_monthly_total: 是否显示当月充电量总计
        config_id: 配置ID（用于查询月度累计）
        report_date: 报表日期，格式 YYYY-MM-DD
    
    Returns:
        str: 文件路径
    """
    if id_name_maps is None:
        id_name_maps = {}
    # 创建reports目录
    reports_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'public', 'reports')
    os.makedirs(reports_dir, exist_ok=True)
    
    # 生成文件名 - 格式：配置名称_几月几日消费记录.xlsx
    # 从 start_time 提取日期（报表数据对应的是开始时间那天的数据）
    try:
        start_dt = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S')
        date_str = f'{start_dt.month}月{start_dt.day}日'
    except:
        date_str = datetime.now().strftime('%m月%d日')
    
    # 如果有补单，添加标记
    supplement_suffix = '_有补单' if has_supplement else ''
    
    filename = f'{config_name}_{date_str}消费记录{supplement_suffix}.xlsx'
    file_path = os.path.join(reports_dir, filename)
    
    # 创建工作簿
    wb = Workbook()
    ws = wb.active
    ws.title = '日报'
    
    # 表头从第1行开始
    header_row = 1
    if field_custom_names:
        if isinstance(field_custom_names, str):
            try:
                field_custom_names = json.loads(field_custom_names)
            except (json.JSONDecodeError, TypeError):
                field_custom_names = {}
    else:
        field_custom_names = {}
    
    # 导入边框样式
    from openpyxl.styles import Border, Side
    
    thin_border = Border(
        left=Side(style='thin', color='000000'),
        right=Side(style='thin', color='000000'),
        top=Side(style='thin', color='000000'),
        bottom=Side(style='thin', color='000000')
    )
    
    header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
    header_font = Font(bold=True, color='FFFFFF', size=11)
    header_alignment = Alignment(horizontal='center', vertical='center')
    
    even_row_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
    
    sum_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
    sum_font = Font(bold=True, size=11)
    
    monthly_fill = PatternFill(start_color='D6E4F0', end_color='D6E4F0', fill_type='solid')
    monthly_font = Font(bold=True, color='1F4E78', size=11)
    
    # 数字字段列表（靠右对齐，保留三位小数）
    numeric_fields = {
        # 电量类
        'charge_degree', 'charge_begin_degree', 'charge_end_degree', 'charge_ah',
        'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity',
        'charge_times_degree', 'subsidy_degree',
        # 金额类（应收）
        'receivable_electric_fee', 'receivable_service_fee', 'receivable_total_fee',
        # 金额类（实际）
        'charge_elecfee_amount', 'charge_elecfee_cost_amount', 'charge_service_amount', 'charging_amt',
        # 金额类（支付）
        'actual_pay_amount', 'pay_amount',
        # 金额类（单价）
        'charge_unit_price', 'charge_unit_cost', 'charge_unit_service_fee',
        # 金额类（结算）
        'settle_electric_fee', 'settle_service_fee', 'settle_fee', 'settle_coupon_amount',
        # 金额类（优惠券）
        'coupon_amount', 'coupon_total_amount', 'elecfee_coupon_amount', 'servicefee_coupon_amount',
        # 金额类（发票）
        'invoice_fee',
        # 金额类（活动）
        'activity_electric_fee', 'activity_service_fee', 'activity_total_fee',
        'company_activity_total_fee', 'company_activity_service_fee', 'company_activity_electric_fee',
        # 金额类（补贴/运营商/佣金）
        'subsidy_fee', 'operator_income', 'plat_service_fee',
        'com_service_fee', 'com_electric_fee', 'com_total_fee', 'com_charge_discount',
        # 兼容字段（旧版命名）
        'total_money', 'total_amount', 'pay_money', 'discount_money', 'service_money',
        'electricity_money', 'parking_money', 'other_money', 'peak_valley_diff_money',
        # 时长类
        'total_duration', 'charging_duration', 'charge_duration',
        # SOC类
        'start_soc', 'end_soc', 'total_soc', 'charge_begin_soc', 'charge_end_soc', 'charge_cur_soc',
    }
    
    # 保留三位小数的字段（金额、电量等）
    decimal3_fields = numeric_fields
    
    # 写入表头
    # 第1列：序号
    cell = ws.cell(row=header_row, column=1)
    cell.value = '序号'
    cell.font = header_font
    cell.fill = header_fill
    cell.alignment = header_alignment
    cell.border = thin_border
    
    has_custom_service_fee = custom_service_fee_price is not None and custom_service_fee_price != ''
    
    for col_idx, field in enumerate(selected_fields, 2):
        cell = ws.cell(row=header_row, column=col_idx)
        
        if field == 'custom_service_fee':
            if custom_service_fee_name and str(custom_service_fee_name).strip():
                display_name = str(custom_service_fee_name).strip()
            elif has_custom_service_fee:
                display_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
            else:
                display_name = '自定义服务费'
        elif field == 'custom_total_amount' or field == 'total_amount':
            if total_amount_name and str(total_amount_name).strip():
                display_name = str(total_amount_name).strip()
            else:
                display_name = '自定义实收总金额'
        elif field in field_custom_names and field_custom_names[field]:
            display_name = field_custom_names[field]
        elif field in id_name_maps and id_name_maps[field]:
            display_name = get_field_display_name(field).replace('ID', '')
        else:
            display_name = get_field_display_name(field)
        
        cell.value = display_name
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = header_alignment
        cell.border = thin_border
    
    ws.row_dimensions[header_row].height = 25
    
    # 写入数据
    data_start_row = header_row + 1
    for row_idx, order in enumerate(orders, data_start_row):
        is_even = (row_idx - data_start_row) % 2 == 1
        
        # 第1列：序号
        seq_num = row_idx - data_start_row + 1
        seq_cell = ws.cell(row=row_idx, column=1)
        seq_cell.value = seq_num
        seq_cell.border = thin_border
        seq_cell.alignment = Alignment(horizontal='center', vertical='center')
        if is_even:
            seq_cell.fill = even_row_fill
        
        for col_idx, field in enumerate(selected_fields, 2):
            cell = ws.cell(row=row_idx, column=col_idx)
            
            if field == 'custom_service_fee':
                # 直接使用订单数据中已计算好的值
                value = order.get('custom_service_fee', '')
            elif field == 'custom_total_amount' or field == 'total_amount':
                # 直接使用订单数据中已计算好的值（兼容旧版字段名 total_amount）
                value = order.get('custom_total_amount', order.get('total_amount', ''))
            else:
                value = order.get(field, '')
                
                # 格式化时间字段
                if field in ['report_time', 'start_time', 'end_time', 'create_time', 'update_time', 'pay_time']:
                    if isinstance(value, datetime):
                        value = value.strftime('%Y-%m-%d %H:%M:%S')
                
                # 将ID转换为名称
                if field in id_name_maps and value is not None and value != '':
                    name_map = id_name_maps[field]
                    name_value = name_map.get(str(value))
                    if name_value:
                        value = name_value
            
            cell.value = value
            cell.border = thin_border
            
            # 数字字段靠右对齐，其他居中或靠左
            if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
                cell.alignment = Alignment(horizontal='right', vertical='center')
                if isinstance(value, (int, float)):
                    cell.number_format = '0.00'
            elif field in ['order_no', 'vehicle_no', 'gun_no', 'connector_no']:
                cell.alignment = Alignment(horizontal='center', vertical='center')
            else:
                cell.alignment = Alignment(horizontal='left', vertical='center')
            
            # 斑马纹（偶数行）
            if is_even:
                cell.fill = even_row_fill
        
        ws.row_dimensions[row_idx].height = 22
    
    # 写入求和行
    last_data_row = header_row + len(orders)
    sum_row = last_data_row + 1
    if sum_fields:
        ws.cell(row=sum_row, column=1).value = '合计'
        ws.cell(row=sum_row, column=1).font = sum_font
        ws.cell(row=sum_row, column=1).fill = sum_fill
        ws.cell(row=sum_row, column=1).alignment = Alignment(horizontal='center', vertical='center')
        ws.cell(row=sum_row, column=1).border = thin_border
        
        for col_idx, field in enumerate(selected_fields, 2):
            cell = ws.cell(row=sum_row, column=col_idx)
            cell.fill = sum_fill
            cell.border = thin_border
            
            if field == 'custom_service_fee':
                # 直接使用订单中已计算好的值求和，确保与数据行一致
                if 'custom_service_fee' in sum_results:
                    value = sum_results['custom_service_fee']
                elif has_custom_service_fee:
                    total_charge_degree = sum_results.get('charge_degree', 0)
                    value = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
                else:
                    value = ''
                cell.value = value
                cell.font = sum_font
                cell.alignment = Alignment(horizontal='right', vertical='center')
                cell.number_format = '0.00'
            elif field == 'custom_total_amount' or field == 'total_amount':
                # 直接使用订单中已计算好的值求和，确保与数据行一致
                if 'custom_total_amount' in sum_results:
                    value = sum_results['custom_total_amount']
                else:
                    total_actual_money = sum_results.get('charge_elecfee_amount', 0)
                    if has_custom_service_fee:
                        total_charge_degree = sum_results.get('charge_degree', 0)
                        total_custom_fee = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
                        value = round(float(total_actual_money) + total_custom_fee, 2)
                    else:
                        value = round(float(total_actual_money), 2)
                cell.value = value
                cell.font = sum_font
                cell.alignment = Alignment(horizontal='right', vertical='center')
                cell.number_format = '0.00'
            elif field in sum_fields and field in sum_results:
                cell.value = sum_results[field]
                cell.font = sum_font
                cell.alignment = Alignment(horizontal='right', vertical='center')
                cell.number_format = '0.000'
        
        ws.row_dimensions[sum_row].height = 25
    
    # 写入当月充电量累计总计行（从求和采集表查询，对账后数据）
    if show_monthly_total and config_id and report_date:
        try:
            from lib.sum_data_collector import get_monthly_charge_degree_total
            month = report_date[:7]
            monthly_result = get_monthly_charge_degree_total(
                config_id=config_id, 
                month=month,
                split_type=split_type,
                split_value=split_value,
                end_date=report_date
            )
            
            if monthly_result['success'] and monthly_result['data']:
                total_degree = monthly_result['data']['total_degree']
                total_days = monthly_result['data']['total_days']
                today_degree_from_table = monthly_result['data'].get('today_degree', 0)
                missing_dates = monthly_result['data'].get('missing_dates', [])
                expected_days = monthly_result['data'].get('expected_days', 0)
                
                # 如果当天的数据还没采集进 sum_data 表，手动加上当天的
                today_charge_degree = sum_results.get('charge_degree', 0)
                if today_degree_from_table == 0 and today_charge_degree > 0:
                    total_degree = round(total_degree + today_charge_degree, 3)
                    total_days = total_days + 1
                    # 加上当天后，缺失日期也相应减少一天
                    if report_date in missing_dates:
                        missing_dates = [d for d in missing_dates if d != report_date]
                
                # 月度总计行（在合计行下面空一行）
                monthly_row = sum_row + 2 if sum_fields else sum_row + 1
                
                # 找 charge_degree 字段所在的列（+1因为序号占了第1列）
                charge_degree_col = None
                for col_idx, field in enumerate(selected_fields, 2):
                    if field == 'charge_degree':
                        charge_degree_col = col_idx
                        break
                
                # 总列数
                total_cols = len(selected_fields) + 2
                
                # 标题文字
                title_text = f'当月累计充电量（共{total_days}天，截止{report_date}）'
                if missing_dates and len(missing_dates) > 0:
                    if len(missing_dates) <= 5:
                        missing_str = '、'.join([d[5:] for d in missing_dates])
                    else:
                        missing_str = '、'.join([d[5:] for d in missing_dates[:5]]) + f'...共{len(missing_dates)}天'
                    title_text += f'\n（缺：{missing_str}）'
                
                # 标题跨列：从第1列到 charge_degree_col 的前一列
                # 如果没有找到充电电量列，就跨到倒数第二列
                title_end_col = charge_degree_col - 1 if charge_degree_col else total_cols - 1
                if title_end_col < 1:
                    title_end_col = 1
                
                # 合并标题单元格
                if title_end_col > 1:
                    ws.merge_cells(start_row=monthly_row, start_column=1, 
                                   end_row=monthly_row, end_column=title_end_col)
                
                # 设置标题单元格
                title_cell = ws.cell(row=monthly_row, column=1)
                title_cell.value = title_text
                title_cell.font = monthly_font
                title_cell.fill = monthly_fill
                title_cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
                title_cell.border = thin_border
                
                # 其他列填充背景色和边框
                for col_idx in range(2, total_cols):
                    cell = ws.cell(row=monthly_row, column=col_idx)
                    cell.fill = monthly_fill
                    cell.border = thin_border
                
                # 数值放在 charge_degree 列
                if charge_degree_col:
                    cell = ws.cell(row=monthly_row, column=charge_degree_col)
                    cell.value = total_degree
                    cell.font = monthly_font
                    cell.alignment = Alignment(horizontal='right', vertical='center')
                    cell.number_format = '0.000'
                
                # 行高
                if missing_dates and len(missing_dates) > 0:
                    ws.row_dimensions[monthly_row].height = 45
                else:
                    ws.row_dimensions[monthly_row].height = 28
        except Exception as e:
            log_error(f"[日报生成] 写入月度总计时出错: {e}", 'report')
    
    # 调整列宽（中文按2个字符宽度计算）
    from openpyxl.utils import get_column_letter
    
    # 序号列固定宽度
    ws.column_dimensions['A'].width = 8
    
    # 计算所有字段的宽度
    col_widths = {}
    numeric_cols = []
    
    for col_idx, field in enumerate(selected_fields, 2):
        header_name = get_field_display_name(field)
        if field in field_custom_names and field_custom_names[field]:
            header_name = field_custom_names[field]
        cn_count = sum(1 for c in str(header_name) if '\u4e00' <= c <= '\u9fff')
        max_length = len(str(header_name)) + cn_count
        
        for row in ws.iter_rows(min_row=data_start_row, max_row=last_data_row, 
                               min_col=col_idx, max_col=col_idx):
            for cell in row:
                if cell.value is not None and cell.value != '':
                    cell_str = str(cell.value)
                    cn_count = sum(1 for c in cell_str if '\u4e00' <= c <= '\u9fff')
                    cell_len = len(cell_str) + cn_count
                    max_length = max(max_length, cell_len)
        
        col_letter = get_column_letter(col_idx)
        col_widths[col_idx] = min(max_length + 2, 50)
        
        # 标记数值类型字段（求和类列）
        if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
            numeric_cols.append(col_idx)
    
    # 计算数值类型列的最大宽度，使所有求和类列宽度一致
    if numeric_cols:
        max_numeric_width = max(col_widths[col] for col in numeric_cols)
        for col_idx in numeric_cols:
            col_letter = get_column_letter(col_idx)
            ws.column_dimensions[col_letter].width = max_numeric_width
    
    # 设置非数值类型列的宽度
    for col_idx, width in col_widths.items():
        if col_idx not in numeric_cols:
            col_letter = get_column_letter(col_idx)
            ws.column_dimensions[col_letter].width = width
    
    # 冻结首行
    ws.freeze_panes = 'A2'
    
    # 保存文件
    wb.save(file_path)
    
    # 返回相对路径
    return f'/reports/{filename}'


def save_report_history(report_date, start_time, end_time, split_type, split_value, 
                        split_name, config_id, config_name, total_orders, total_amount, 
                        sum_results, file_path, status):
    """
    保存日报生成历史记录
    
    Returns:
        int: 历史记录ID
    """
    # 生成ID
    history_id = int(datetime.now().timestamp() * 1000)
    
    log_info(f"[保存历史] 准备保存历史记录", 'report')
    log_info(f"  ID: {history_id}", 'report')
    log_info(f"  file_path: '{file_path}'", 'report')
    log_info(f"  status: {status}", 'report')
    
    sql = """
        INSERT INTO t_daily_report_history 
        (id, report_date, start_time, end_time, split_type, split_value, split_name, 
         config_id, config_name, total_orders, total_amount, sum_results, file_path, status, create_time)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
    """
    
    params = (
        history_id,
        report_date,
        start_time,
        end_time,
        split_type,
        split_value,
        split_name,
        config_id,
        config_name,
        total_orders,
        total_amount,
        json.dumps(sum_results, ensure_ascii=False),
        file_path,
        status
    )
    
    log_info(f"[保存历史] 执行SQL插入...", 'report')
    result = execute_insert(sql, params)
    log_info(f"[保存历史] 插入完成，返回ID: {result}", 'report')
    
    return history_id


def delete_old_history(config_id, report_date, split_type, split_value):
    """
    删除同一配置、同一日期、同一拆分的旧历史记录，包括：
    1. 旧的报表文件
    2. 旧的求和数据（自动采集的）
    3. 旧的历史记录
    
    Args:
        config_id: 配置ID
        report_date: 报表日期（YYYY-MM-DD）
        split_type: 拆分方式
        split_value: 拆分值
    """
    try:
        log_info(f"[删除旧数据] 检查是否有旧数据，配置ID={config_id}, 日期={report_date}, 拆分={split_type}={split_value}", 'report')
        
        # 查询旧的历史记录
        old_histories = execute_query(
            '''SELECT id, file_path FROM t_daily_report_history 
               WHERE config_id = %s AND report_date = %s AND split_type = %s AND split_value = %s''',
            (config_id, report_date, split_type, split_value)
        )
        
        if not old_histories:
            log_info("[删除旧数据] 没有找到旧数据", 'report')
            return
        
        log_info(f"[删除旧数据] 找到 {len(old_histories)} 条旧记录", 'report')
        
        reports_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'public', 'reports')
        
        for history in old_histories:
            history_id = history['id']
            file_path = history.get('file_path', '')
            
            # 删除报表文件
            if file_path:
                try:
                    if file_path.startswith('/reports/'):
                        filename = file_path.replace('/reports/', '')
                    elif file_path.startswith('/public/reports/'):
                        filename = file_path.replace('/public/reports/', '')
                    else:
                        filename = os.path.basename(file_path)
                    
                    full_path = os.path.join(reports_dir, filename)
                    if os.path.exists(full_path):
                        os.remove(full_path)
                        log_info(f"[删除旧数据] 已删除文件: {full_path}", 'report')
                except Exception as e:
                    log_warning(f"[删除旧数据] 删除文件失败: {e}", 'report')
            
            # 删除求和数据（自动采集的）
            try:
                execute_update(
                    '''DELETE FROM t_daily_report_sum_data 
                       WHERE report_date = %s AND config_id = %s 
                       AND split_type = %s AND split_value = %s AND data_source = 'auto' ''',
                    (report_date, config_id, split_type, split_value)
                )
                log_info(f"[删除旧数据] 已删除旧的求和数据", 'report')
            except Exception as e:
                log_warning(f"[删除旧数据] 删除求和数据失败: {e}", 'report')
            
            # 删除历史记录
            try:
                execute_update(
                    'DELETE FROM t_daily_report_history WHERE id = %s',
                    (history_id,)
                )
                log_info(f"[删除旧数据] 已删除历史记录 ID={history_id}", 'report')
            except Exception as e:
                log_warning(f"[删除旧数据] 删除历史记录失败: {e}", 'report')
        
        log_info("[删除旧数据] 旧数据清理完成", 'report')
    except Exception as e:
        log_error(f"[删除旧数据] 异常: {e}", 'report')