"""
AGV 종합 분석 리포트 생성 스크립트
- BMS 배터리 데이터 분석 (0x03: 배터리 상태, 0x04: 셀 전압)
- 상차작업완료 집계
- 충전상태전환 이벤트 분석
- 셀 전압 불균형 분석
- 시간대별 종합 리포트 및 엑셀 차트 생성
"""

import re
from datetime import datetime, timedelta
from collections import defaultdict
import pandas as pd
from openpyxl import load_workbook
from openpyxl.chart import LineChart, Reference, BarChart, AreaChart
from openpyxl.styles import Font, Alignment, PatternFill
import os
import glob

print("=" * 80)
print("AGV 종합 분석 리포트 생성 (셀 전압 분석 포함)")
print("=" * 80)

# ============================================================================
# 1. BMS 배터리 데이터 파싱 (0x03: 배터리 상태)
# ============================================================================

def parse_bms_packet(hex_string):
    """BMS 배터리 상태 패킷 파싱 (0x03)"""
    try:
        bytes_data = [int(x, 16) for x in hex_string.split()]
        if len(bytes_data) < 34 or bytes_data[0] != 0xDD or bytes_data[-1] != 0x77:
            return None
        if bytes_data[1] != 0x03:  # 배터리 상태 정보만
            return None

        volt_raw = (bytes_data[4] << 8) | bytes_data[5]
        voltage = volt_raw / 100.0
        cur_amp = (bytes_data[8] << 8) | bytes_data[9]
        max_amp = (bytes_data[10] << 8) | bytes_data[11]
        level_direct = bytes_data[23]
        temp1_raw = (bytes_data[27] << 8) | bytes_data[28]
        temp1 = (temp1_raw - 2731) / 10.0

        return {
            'voltage': voltage,
            'current_amp': cur_amp,
            'max_amp': max_amp,
            'level': level_direct,
            'temp': temp1
        }
    except:
        return None

def read_bms_log(file_path):
    """BMS 로그 파일 읽기 (배터리 상태)"""
    encodings = ['utf-8', 'cp949', 'euc-kr']
    for encoding in encodings:
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                lines = f.readlines()
            break
        except:
            continue
    else:
        return []

    pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\w+\s+BMS:(.*?)(?=\n|$)'
    battery_data = []

    for line in lines:
        match = re.search(pattern, line)
        if match:
            timestamp_str = match.group(1)
            packet_hex = match.group(2).strip()
            parsed = parse_bms_packet(packet_hex)
            if parsed:
                timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
                battery_data.append({
                    'timestamp': timestamp,
                    **parsed
                })

    return battery_data

# ============================================================================
# 1-2. BMS 셀 전압 데이터 파싱 (0x04: 셀 전압)
# ============================================================================

def parse_cell_voltage_packet(hex_string):
    """BMS 셀 전압 패킷 파싱 (0x04)"""
    try:
        bytes_data = [int(x, 16) for x in hex_string.split()]
        if len(bytes_data) < 23 or bytes_data[0] != 0xDD or bytes_data[-1] != 0x77:
            return None
        if bytes_data[1] != 0x04:  # 셀 전압 정보만
            return None

        # 8개 셀 전압 추출
        voltages = []
        for i in range(8):
            v_raw = (bytes_data[4 + i*2] << 8) | bytes_data[5 + i*2]
            voltages.append(v_raw / 1000.0)

        return {
            'cell1': voltages[0],
            'cell2': voltages[1],
            'cell3': voltages[2],
            'cell4': voltages[3],
            'cell5': voltages[4],
            'cell6': voltages[5],
            'cell7': voltages[6],
            'cell8': voltages[7],
            'max_voltage': max(voltages),
            'min_voltage': min(voltages),
            'voltage_diff': max(voltages) - min(voltages),
            'avg_voltage': sum(voltages) / len(voltages)
        }
    except:
        return None

def read_cell_voltage_log(file_path):
    """셀 전압 로그 파일 읽기"""
    encodings = ['utf-8', 'cp949', 'euc-kr']
    for encoding in encodings:
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                lines = f.readlines()
            break
        except:
            continue
    else:
        return []

    pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\w+\s+BMS:(.*?)(?=\n|$)'
    cell_data = []

    for line in lines:
        match = re.search(pattern, line)
        if match:
            timestamp_str = match.group(1)
            packet_hex = match.group(2).strip()
            parsed = parse_cell_voltage_packet(packet_hex)
            if parsed:
                timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
                cell_data.append({
                    'timestamp': timestamp,
                    **parsed
                })

    return cell_data

# ============================================================================
# 2. 상차작업완료 카운트
# ============================================================================

def read_loading_complete(file_path):
    """상차작업완료 메시지 추출"""
    encodings = ['utf-8', 'cp949', 'euc-kr']
    for encoding in encodings:
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                content = f.read()
            break
        except:
            continue
    else:
        return []

    pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*상차작업완료\(([^)]+)\)'
    matches = re.findall(pattern, content)

    results = []
    for timestamp_str, location in matches:
        timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
        results.append({
            'timestamp': timestamp,
            'location': location
        })

    return results

# ============================================================================
# 3. 충전상태전환 이벤트
# ============================================================================

def read_charge_status(file_path):
    """충전상태전환 메시지 추출"""
    encodings = ['utf-8', 'cp949', 'euc-kr']
    for encoding in encodings:
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                lines = f.readlines()
            break
        except:
            continue
    else:
        return []

    pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*충전상태전환\s+(True|False)'
    results = []

    for line in lines:
        match = re.search(pattern, line)
        if match:
            timestamp_str = match.group(1)
            status = match.group(2)
            timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
            results.append({
                'timestamp': timestamp,
                'status': status == 'True'
            })

    return results

# ============================================================================
# 4. 데이터 읽기
# ============================================================================

print("\n데이터 로딩 중...")

# 현재 실행 폴더 기준 (서브폴더 포함)
base_path = os.getcwd()
print(f"  분석 폴더: {base_path} (서브폴더 포함)")

# 파일 패턴으로 자동 검색 (재귀 검색)
# BMS 파일들 찾기 (*_bms.txt)
bms_files = sorted(glob.glob(os.path.join(base_path, "**", "*_bms.txt"), recursive=True))
print(f"  BMS 파일: {len(bms_files)}개 발견")
for f in bms_files:
    rel_path = os.path.relpath(f, base_path)
    print(f"    - {rel_path}")

# 운용기록 로그 파일들 찾기 (202*.txt, 단 _bms.txt 제외)
log_files = sorted([f for f in glob.glob(os.path.join(base_path, "**", "202*.txt"), recursive=True)
                    if not f.endswith("_bms.txt")])
print(f"  운용기록 파일: {len(log_files)}개 발견")
for f in log_files:
    rel_path = os.path.relpath(f, base_path)
    print(f"    - {rel_path}")

# BMS 배터리 상태 데이터 (0x03)
all_battery = []
for bms_file in bms_files:
    data = read_bms_log(bms_file)
    all_battery.extend(data)
    rel_path = os.path.relpath(bms_file, base_path)
    print(f"    {rel_path}: {len(data)}개 배터리 데이터")
all_battery.sort(key=lambda x: x['timestamp'])

print(f"  배터리 데이터 총합: {len(all_battery)}개")

# BMS 셀 전압 데이터 (0x04)
all_cells = []
for bms_file in bms_files:
    data = read_cell_voltage_log(bms_file)
    all_cells.extend(data)
    rel_path = os.path.relpath(bms_file, base_path)
    print(f"    {rel_path}: {len(data)}개 셀 전압 데이터")
all_cells.sort(key=lambda x: x['timestamp'])

print(f"  셀 전압 데이터 총합: {len(all_cells)}개")

# 상차작업완료 데이터
all_loading = []
for log_file in log_files:
    data = read_loading_complete(log_file)
    all_loading.extend(data)
    rel_path = os.path.relpath(log_file, base_path)
    print(f"    {rel_path}: {len(data)}건 작업완료")
all_loading.sort(key=lambda x: x['timestamp'])

print(f"  상차작업완료 총합: {len(all_loading)}건")

# 충전상태전환 데이터
all_charge = []
for log_file in log_files:
    data = read_charge_status(log_file)
    all_charge.extend(data)
    rel_path = os.path.relpath(log_file, base_path)
    print(f"    {rel_path}: {len(data)}건 충전이벤트")
all_charge.sort(key=lambda x: x['timestamp'])

print(f"  충전상태전환 총합: {len(all_charge)}건")

# ============================================================================
# 4-2. 셀 불균형 분석
# ============================================================================

print("\n셀 불균형 분석 중...")

if all_cells:
    # 불균형 기준: 0.1V 이상 차이
    critical_imbalance = [c for c in all_cells if c['voltage_diff'] > 0.1]
    warning_imbalance = [c for c in all_cells if 0.05 < c['voltage_diff'] <= 0.1]

    print(f"  심각한 불균형 (>0.1V): {len(critical_imbalance)}건")
    print(f"  경고 수준 불균형 (0.05~0.1V): {len(warning_imbalance)}건")

    # 일별 셀 전압 분석
    from collections import defaultdict
    daily_cells = defaultdict(list)
    for c in all_cells:
        date_key = c['timestamp'].strftime('%Y-%m-%d')
        daily_cells[date_key].append(c)

    for date_key in sorted(daily_cells.keys()):
        day_data = daily_cells[date_key]
        print(f"\n[{date_key} 셀 전압 분석]")
        print(f"  측정 건수: {len(day_data)}건")

        max_diff = max(c['voltage_diff'] for c in day_data)
        avg_diff = sum(c['voltage_diff'] for c in day_data) / len(day_data)
        print(f"  최대 불균형: {max_diff:.3f}V")
        print(f"  평균 불균형: {avg_diff:.3f}V")

        # 최대 불균형 시점 찾기
        max_imbalance = max(day_data, key=lambda x: x['voltage_diff'])
        print(f"  최대 불균형 시점: {max_imbalance['timestamp'].strftime('%H:%M:%S')}")
        print(f"  셀 전압: C1={max_imbalance['cell1']:.3f}V, C2={max_imbalance['cell2']:.3f}V, "
              f"C3={max_imbalance['cell3']:.3f}V, C4={max_imbalance['cell4']:.3f}V")
        print(f"           C5={max_imbalance['cell5']:.3f}V, C6={max_imbalance['cell6']:.3f}V, "
              f"C7={max_imbalance['cell7']:.3f}V, C8={max_imbalance['cell8']:.3f}V")
        print(f"  전압 차이: {max_imbalance['voltage_diff']:.3f}V "
              f"(최고 {max_imbalance['max_voltage']:.3f}V - 최저 {max_imbalance['min_voltage']:.3f}V)")

        # 해당 일의 심각한 불균형 건수
        day_critical = [c for c in day_data if c['voltage_diff'] > 0.1]
        day_warning = [c for c in day_data if 0.05 < c['voltage_diff'] <= 0.1]
        print(f"  심각한 불균형: {len(day_critical)}건, 경고 수준: {len(day_warning)}건")

# ============================================================================
# 5. 시간대별 집계 (1시간 단위)
# ============================================================================

print("\n시간대별 데이터 집계 중...")

# 시작/종료 시간 결정
if all_battery:
    start_time = all_battery[0]['timestamp']
    end_time = all_battery[-1]['timestamp']
else:
    start_time = datetime(2025, 11, 5, 0, 0, 0)
    end_time = datetime(2025, 11, 6, 23, 59, 59)

# 1시간 단위 시간 슬롯 생성
time_slots = []
current = start_time.replace(minute=0, second=0, microsecond=0)
while current <= end_time:
    time_slots.append(current)
    current += timedelta(hours=1)

# 각 시간대별 데이터 집계
timeline_data = []

for slot in time_slots:
    slot_end = slot + timedelta(hours=1)

    # 배터리 데이터 평균
    slot_battery = [b for b in all_battery if slot <= b['timestamp'] < slot_end]
    if slot_battery:
        avg_voltage = sum(b['voltage'] for b in slot_battery) / len(slot_battery)
        avg_amp = sum(b['current_amp'] for b in slot_battery) / len(slot_battery)
        avg_level = sum(b['level'] for b in slot_battery) / len(slot_battery)
        avg_temp = sum(b['temp'] for b in slot_battery) / len(slot_battery)
        battery_count = len(slot_battery)
    else:
        avg_voltage = avg_amp = avg_level = avg_temp = battery_count = 0

    # 작업 완료 카운트
    slot_loading = [l for l in all_loading if slot <= l['timestamp'] < slot_end]
    loading_count = len(slot_loading)

    # 작업 위치별 카운트
    location_counts = defaultdict(int)
    for l in slot_loading:
        location_counts[l['location']] += 1

    # 충전 상태 - 현재 시간이 충전 구간에 포함되는지 확인
    is_charging = False
    for c in all_charge:
        if c['timestamp'] <= slot:
            is_charging = c['status']
        elif c['timestamp'] > slot_end:
            break

    # 슬롯 내 충전상태전환 이벤트 확인
    slot_charge = [c for c in all_charge if slot <= c['timestamp'] < slot_end]
    if slot_charge:
        is_charging = slot_charge[-1]['status']

    charging = "충전중" if is_charging else "-"
    charging_indicator = 100 if is_charging else 0

    timeline_data.append({
        '시간대': slot.strftime('%Y-%m-%d %H:%M'),
        '평균전압(V)': round(avg_voltage, 2) if avg_voltage > 0 else '',
        '평균용량(mAh)': int(avg_amp) if avg_amp > 0 else '',
        '평균잔량(%)': int(avg_level) if avg_level > 0 else '',
        '평균온도(°C)': round(avg_temp, 1) if avg_temp > 0 else '',
        '작업완료건수': loading_count,
        'F1': location_counts.get('F1', 0),
        'F2': location_counts.get('F2', 0),
        'F3': location_counts.get('F3', 0),
        'F4': location_counts.get('F4', 0),
        'F5': location_counts.get('F5', 0),
        'F6': location_counts.get('F6', 0),
        '충전상태': charging,
        '충전구간': charging_indicator,
        '배터리측정수': battery_count
    })

print(f"  시간대별 데이터: {len(timeline_data)}개 슬롯")

# ============================================================================
# 5-2. 일자별 집계
# ============================================================================

print("\n일자별 데이터 집계 중...")

# 일자별 작업 완료 건수 집계
daily_summary = defaultdict(lambda: {
    'date': '',
    'total_work': 0,
    'F1': 0, 'F2': 0, 'F3': 0, 'F4': 0, 'F5': 0, 'F6': 0,
    'HOME': 0,
    'charge_count': 0,
    'battery_count': 0,
    'avg_battery_level': 0
})

# 작업 완료 집계
for work in all_loading:
    date_key = work['timestamp'].strftime('%Y-%m-%d')
    daily_summary[date_key]['date'] = date_key
    daily_summary[date_key]['total_work'] += 1
    daily_summary[date_key][work['location']] += 1

# 충전 이벤트 집계
for charge in all_charge:
    date_key = charge['timestamp'].strftime('%Y-%m-%d')
    daily_summary[date_key]['charge_count'] += 1

# 배터리 데이터 집계
battery_by_day = defaultdict(list)
for bat in all_battery:
    date_key = bat['timestamp'].strftime('%Y-%m-%d')
    battery_by_day[date_key].append(bat['level'])

for date_key, levels in battery_by_day.items():
    daily_summary[date_key]['battery_count'] = len(levels)
    daily_summary[date_key]['avg_battery_level'] = sum(levels) / len(levels)

# DataFrame 생성
daily_data = []
for date_key in sorted(daily_summary.keys()):
    data = daily_summary[date_key]
    daily_data.append({
        '일자': data['date'],
        '총작업건수': data['total_work'],
        'F1': data['F1'],
        'F2': data['F2'],
        'F3': data['F3'],
        'F4': data['F4'],
        'F5': data['F5'],
        'F6': data['F6'],
        '충전이벤트': data['charge_count']
    })

print(f"  일자별 데이터: {len(daily_data)}일")

# ============================================================================
# 5-3. 일자별 교대조(Shift)별 집계
# ============================================================================

print("\n교대조별 데이터 집계 중...")

def get_shift(timestamp):
    """시간대별 교대조 분류"""
    hour = timestamp.hour
    if 6 <= hour < 14:
        return 'Day'
    elif 14 <= hour < 22:
        return 'Swing'
    else:  # 22:00~06:00
        return 'Night'

# 일자별 교대조별 작업 집계
shift_summary = defaultdict(lambda: {'date': '', 'Day': 0, 'Swing': 0, 'Night': 0})

for work in all_loading:
    date_key = work['timestamp'].strftime('%Y-%m-%d')
    shift = get_shift(work['timestamp'])
    shift_summary[date_key]['date'] = date_key
    shift_summary[date_key][shift] += 1

# DataFrame 생성
shift_data = []
for date_key in sorted(shift_summary.keys()):
    data = shift_summary[date_key]
    total = data['Day'] + data['Swing'] + data['Night']
    avg = round(total / 3, 1) if total > 0 else 0
    shift_data.append({
        '일자': data['date'],
        'day': data['Day'],
        'swing': data['Swing'],
        'night': data['Night'],
        '합계': total,
        '평균': avg
    })

print(f"  교대조별 데이터: {len(shift_data)}일")

# ============================================================================
# 6. 엑셀 리포트 생성
# ============================================================================

print("\n엑셀 리포트 생성 중...")

# 출력 파일명 동적 생성 (시작일~종료일)
if all_battery:
    start_date = all_battery[0]['timestamp'].strftime('%Y%m%d')
    end_date = all_battery[-1]['timestamp'].strftime('%Y%m%d')
    output_filename = f"agv_log_report_{start_date}~{end_date}.xlsx"
else:
    output_filename = "agv_log_report.xlsx"

output_file = os.path.join(base_path, output_filename)
print(f"  출력 파일: {output_filename}")

# DataFrame 생성
df_timeline = pd.DataFrame(timeline_data)

# 배터리 상세 데이터
df_battery = pd.DataFrame([{
    '시간': b['timestamp'].strftime('%Y-%m-%d %H:%M:%S'),
    '전압(V)': round(b['voltage'], 2),
    '남은용량(mAh)': b['current_amp'],
    '총용량(mAh)': b['max_amp'],
    '잔량(%)': b['level'],
    '온도(°C)': round(b['temp'], 1)
} for b in all_battery])

# 작업 상세 데이터
df_loading = pd.DataFrame([{
    '시간': l['timestamp'].strftime('%Y-%m-%d %H:%M:%S'),
    '위치': l['location']
} for l in all_loading])

# 충전 이벤트 데이터
df_charge = pd.DataFrame([{
    '시간': c['timestamp'].strftime('%Y-%m-%d %H:%M:%S'),
    '충전상태': '시작' if c['status'] else '종료'
} for c in all_charge])

# 셀 전압 상세 데이터
df_cells = pd.DataFrame([{
    '시간': c['timestamp'].strftime('%Y-%m-%d %H:%M:%S'),
    'Cell1(V)': round(c['cell1'], 3),
    'Cell2(V)': round(c['cell2'], 3),
    'Cell3(V)': round(c['cell3'], 3),
    'Cell4(V)': round(c['cell4'], 3),
    'Cell5(V)': round(c['cell5'], 3),
    'Cell6(V)': round(c['cell6'], 3),
    'Cell7(V)': round(c['cell7'], 3),
    'Cell8(V)': round(c['cell8'], 3),
    '최고전압(V)': round(c['max_voltage'], 3),
    '최저전압(V)': round(c['min_voltage'], 3),
    '전압차(V)': round(c['voltage_diff'], 3),
    '평균전압(V)': round(c['avg_voltage'], 3)
} for c in all_cells]) if all_cells else pd.DataFrame()

# 일자별 요약 DataFrame
df_daily = pd.DataFrame(daily_data)
df_shift = pd.DataFrame(shift_data)

# 엑셀 저장
with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
    df_daily.to_excel(writer, sheet_name='일자별작업요약', index=False)
    # 교대조별 데이터를 같은 시트에 추가 (일자별 데이터 아래 3행 띄우고)
    df_shift.to_excel(writer, sheet_name='일자별작업요약', startrow=len(df_daily)+3, index=False)

    df_timeline.to_excel(writer, sheet_name='시간대별종합', index=False)
    df_battery.to_excel(writer, sheet_name='배터리상세', index=False)
    df_loading.to_excel(writer, sheet_name='작업상세', index=False)
    df_charge.to_excel(writer, sheet_name='충전이벤트', index=False)
    if not df_cells.empty:
        df_cells.to_excel(writer, sheet_name='셀전압상세', index=False)

# ============================================================================
# 7. 차트 추가
# ============================================================================

print("차트 생성 중...")

wb = load_workbook(output_file)

# ============================================================================
# 7-1. 일자별작업요약 시트 스타일 및 차트
# ============================================================================

ws_daily = wb['일자별작업요약']

# 헤더 스타일
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
header_font = Font(color="FFFFFF", bold=True)

for cell in ws_daily[1]:
    cell.fill = header_fill
    cell.font = header_font
    cell.alignment = Alignment(horizontal='center')

# 열 너비 조정
ws_daily.column_dimensions['A'].width = 12
for col in ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']:
    ws_daily.column_dimensions[col].width = 12

# 일자별 작업 건수 차트
chart_daily_work = BarChart()
chart_daily_work.type = "col"
chart_daily_work.title = "일자별 작업 완료 건수"
chart_daily_work.y_axis.title = '작업 건수'
chart_daily_work.x_axis.title = '일자'
chart_daily_work.height = 12
chart_daily_work.width = 20

# 총작업건수 데이터
data = Reference(ws_daily, min_col=2, min_row=1, max_row=len(daily_data)+1)
cats = Reference(ws_daily, min_col=1, min_row=2, max_row=len(daily_data)+1)
chart_daily_work.add_data(data, titles_from_data=True)
chart_daily_work.set_categories(cats)

ws_daily.add_chart(chart_daily_work, "N2")

# 일자별 위치별 작업 건수 차트 (누적 막대)
chart_daily_location = BarChart()
chart_daily_location.type = "col"
chart_daily_location.grouping = "stacked"
chart_daily_location.title = "일자별 위치별 작업 건수 (누적)"
chart_daily_location.y_axis.title = '작업 건수'
chart_daily_location.x_axis.title = '일자'
chart_daily_location.height = 12
chart_daily_location.width = 20

# F1~F6 데이터 (3~8열)
data = Reference(ws_daily, min_col=3, max_col=8, min_row=1, max_row=len(daily_data)+1)
cats = Reference(ws_daily, min_col=1, min_row=2, max_row=len(daily_data)+1)
chart_daily_location.add_data(data, titles_from_data=True)
chart_daily_location.set_categories(cats)

ws_daily.add_chart(chart_daily_location, "N22")

# 교대조별 데이터 영역 스타일 및 차트
shift_start_row = len(daily_data) + 4  # 일자별 데이터 + 빈 행 + 헤더

# 교대조별 헤더 스타일
for col_idx in range(1, 7):  # A~F 열 (일자, day, swing, night, 합계, 평균)
    cell = ws_daily.cell(row=shift_start_row, column=col_idx)
    cell.font = Font(bold=True, color="FFFFFF")
    cell.fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
    cell.alignment = Alignment(horizontal='center')

# 교대조별 작업 건수 차트 (혼합 차트: 막대 + 선)
chart_shift = BarChart()
chart_shift.type = "col"
chart_shift.grouping = "clustered"
chart_shift.title = "일자별 교대조별 작업 건수"
chart_shift.y_axis.title = '작업 건수'
chart_shift.x_axis.title = '일자'
chart_shift.height = 12
chart_shift.width = 20

# Day, Swing, Night 데이터 (막대 차트)
data = Reference(ws_daily, min_col=2, max_col=4, min_row=shift_start_row, max_row=shift_start_row+len(shift_data))
cats = Reference(ws_daily, min_col=1, min_row=shift_start_row+1, max_row=shift_start_row+len(shift_data))
chart_shift.add_data(data, titles_from_data=True)
chart_shift.set_categories(cats)

# 데이터 레이블 추가 (숫자만 표시)
from openpyxl.chart.label import DataLabelList
for series in chart_shift.series:
    series.dLbls = DataLabelList()
    series.dLbls.showVal = True
    series.dLbls.showCatName = False
    series.dLbls.showSerName = False
    series.dLbls.showPercent = False
    series.dLbls.showLeaderLines = False

# 평균 데이터 (선 차트)
line_chart = LineChart()
line_data = Reference(ws_daily, min_col=6, min_row=shift_start_row, max_row=shift_start_row+len(shift_data))
line_chart.add_data(line_data, titles_from_data=True)
line_chart.set_categories(cats)

# 선 차트에 데이터 레이블 추가
for series in line_chart.series:
    series.dLbls = DataLabelList()
    series.dLbls.showVal = True
    series.dLbls.showCatName = False
    series.dLbls.showSerName = False
    series.dLbls.showPercent = False
    series.dLbls.showLeaderLines = False

# 혼합 차트 조합
chart_shift += line_chart

ws_daily.add_chart(chart_shift, "N42")

# ============================================================================
# 7-2. 시간대별종합 시트 스타일
# ============================================================================

ws = wb['시간대별종합']

# 헤더 스타일
for cell in ws[1]:
    cell.fill = header_fill
    cell.font = header_font
    cell.alignment = Alignment(horizontal='center')

# 열 너비 조정
ws.column_dimensions['A'].width = 18
ws.column_dimensions['B'].width = 12
ws.column_dimensions['C'].width = 14
ws.column_dimensions['D'].width = 12
ws.column_dimensions['E'].width = 12
ws.column_dimensions['F'].width = 12
ws.column_dimensions['L'].width = 12

# 차트 1: 배터리 잔량 추이
chart1 = LineChart()
chart1.title = "배터리 잔량 추이"
chart1.style = 10
chart1.y_axis.title = '배터리 잔량 (%)'
chart1.x_axis.title = '시간대'
chart1.height = 10
chart1.width = 20

data = Reference(ws, min_col=4, min_row=1, max_row=len(timeline_data)+1)
cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1)
chart1.add_data(data, titles_from_data=True)
chart1.set_categories(cats)

ws.add_chart(chart1, "N2")

# 차트 2: 작업 건수 추이
chart2 = BarChart()
chart2.type = "col"
chart2.title = "시간대별 작업 완료 건수"
chart2.y_axis.title = '작업 건수'
chart2.x_axis.title = '시간대'
chart2.height = 10
chart2.width = 20

data = Reference(ws, min_col=6, min_row=1, max_row=len(timeline_data)+1)
cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1)
chart2.add_data(data, titles_from_data=True)
chart2.set_categories(cats)

ws.add_chart(chart2, "N22")

# 차트 3: 전압 추이
chart3 = LineChart()
chart3.title = "배터리 전압 추이"
chart3.style = 12
chart3.y_axis.title = '전압 (V)'
chart3.x_axis.title = '시간대'
chart3.height = 10
chart3.width = 20

data = Reference(ws, min_col=2, min_row=1, max_row=len(timeline_data)+1)
cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1)
chart3.add_data(data, titles_from_data=True)
chart3.set_categories(cats)

ws.add_chart(chart3, "N42")

# 차트 4: 종합 혼합 차트 (배터리 잔량 + 전압 + 작업횟수 + 충전구간)
chart4_area = AreaChart()
chart4_area.title = "시간대별 종합 현황 (배터리/전압/작업/충전)"
chart4_area.style = 27
chart4_area.y_axis.title = '배터리 잔량 (%) / 전압 (V × 10)'
chart4_area.x_axis.title = '시간대'
chart4_area.height = 15
chart4_area.width = 30

# 충전 구간 배경 (면적 차트)
charging_data = Reference(ws, min_col=13, min_row=1, max_row=len(timeline_data)+1)
cats = Reference(ws, min_col=1, min_row=2, max_row=len(timeline_data)+1)
chart4_area.add_data(charging_data, titles_from_data=True)
chart4_area.set_categories(cats)

# 배터리 잔량 선 추가
battery_data = Reference(ws, min_col=4, min_row=1, max_row=len(timeline_data)+1)
chart4_area.add_data(battery_data, titles_from_data=True)

# 전압 데이터 추가
voltage_data = Reference(ws, min_col=2, min_row=1, max_row=len(timeline_data)+1)
chart4_area.add_data(voltage_data, titles_from_data=True)

# 보조 차트: 작업횟수 (오른쪽 Y축 바 차트)
chart4_bar = BarChart()
chart4_bar.type = "col"
chart4_bar.grouping = "standard"

work_data = Reference(ws, min_col=6, min_row=1, max_row=len(timeline_data)+1)
chart4_bar.add_data(work_data, titles_from_data=True)
chart4_bar.set_categories(cats)

# 복합 차트 조합
chart4_area.y_axis.crossAx = 500
chart4_bar.y_axis.axId = 500
chart4_bar.y_axis.title = "작업 횟수"
chart4_area += chart4_bar

ws.add_chart(chart4_area, "A72")

# ============================================================================
# 8. 셀 전압 시트 스타일 및 차트
# ============================================================================

if all_cells and '셀전압상세' in wb.sheetnames:
    print("셀 전압 차트 생성 중...")

    ws_cells = wb['셀전압상세']

    # 헤더 스타일
    for c_idx, col_name in enumerate(df_cells.columns, start=1):
        cell = ws_cells.cell(row=1, column=c_idx)
        cell.font = Font(bold=True, color="FFFFFF")
        cell.fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
        cell.alignment = Alignment(horizontal='center')

    # 열 너비 조정
    ws_cells.column_dimensions['A'].width = 20
    for col in ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M']:
        ws_cells.column_dimensions[col].width = 12

    # 셀 전압 차이가 큰 행 강조 표시
    red_fill = PatternFill(start_color="FFCCCC", end_color="FFCCCC", fill_type="solid")
    yellow_fill = PatternFill(start_color="FFFFCC", end_color="FFFFCC", fill_type="solid")

    for row_idx in range(2, len(df_cells) + 2):
        voltage_diff = ws_cells.cell(row=row_idx, column=12).value
        if voltage_diff and voltage_diff > 0.1:
            for col_idx in range(1, 14):
                ws_cells.cell(row=row_idx, column=col_idx).fill = red_fill
        elif voltage_diff and voltage_diff > 0.05:
            for col_idx in range(1, 14):
                ws_cells.cell(row=row_idx, column=col_idx).fill = yellow_fill

    # 차트 5: 셀별 전압 추이
    chart5 = LineChart()
    chart5.title = "셀별 전압 추이"
    chart5.style = 10
    chart5.y_axis.title = '전압 (V)'
    chart5.x_axis.title = '시간대'
    chart5.height = 15
    chart5.width = 30

    # 각 셀 데이터 추가
    for col_idx in range(2, 10):  # Cell1~Cell8
        data = Reference(ws_cells, min_col=col_idx, min_row=1, max_row=len(df_cells)+1)
        chart5.add_data(data, titles_from_data=True)

    cats = Reference(ws_cells, min_col=1, min_row=2, max_row=len(df_cells)+1)
    chart5.set_categories(cats)

    ws_cells.add_chart(chart5, "O2")

    # 차트 6: 전압 불균형 추이
    chart6 = LineChart()
    chart6.title = "셀 전압 불균형 추이 (최고-최저)"
    chart6.style = 12
    chart6.y_axis.title = '전압 차이 (V)'
    chart6.x_axis.title = '시간대'
    chart6.height = 12
    chart6.width = 30

    data = Reference(ws_cells, min_col=12, min_row=1, max_row=len(df_cells)+1)
    chart6.add_data(data, titles_from_data=True)
    chart6.set_categories(cats)

    ws_cells.add_chart(chart6, "O32")

wb.save(output_file)

print(f"\n리포트 생성 완료: {output_file}")

# ============================================================================
# 9. 요약 통계
# ============================================================================

print("\n" + "=" * 80)
print("종합 분석 요약")
print("=" * 80)

print(f"\n[분석 기간]")
print(f"  {start_time.strftime('%Y-%m-%d %H:%M')} ~ {end_time.strftime('%Y-%m-%d %H:%M')}")

print(f"\n[배터리 통계]")
if all_battery:
    print(f"  최소 잔량: {min(b['level'] for b in all_battery)}%")
    print(f"  최대 잔량: {max(b['level'] for b in all_battery)}%")
    print(f"  평균 잔량: {sum(b['level'] for b in all_battery) / len(all_battery):.1f}%")
    print(f"  최저 전압: {min(b['voltage'] for b in all_battery):.2f}V")
    print(f"  최고 전압: {max(b['voltage'] for b in all_battery):.2f}V")

print(f"\n[작업 통계]")
print(f"  총 작업 완료: {len(all_loading)}건")
location_stats = defaultdict(int)
for l in all_loading:
    location_stats[l['location']] += 1
for loc in sorted(location_stats.keys()):
    print(f"  {loc}: {location_stats[loc]}건")

print(f"\n[충전 통계]")
charge_on_count = sum(1 for c in all_charge if c['status'])
charge_off_count = sum(1 for c in all_charge if not c['status'])
print(f"  충전 시작: {charge_on_count}회")
print(f"  충전 종료: {charge_off_count}회")

# 셀 전압 통계
if all_cells:
    print(f"\n[셀 전압 통계]")
    print(f"  최대 불균형: {max(c['voltage_diff'] for c in all_cells):.3f}V")
    print(f"  평균 불균형: {sum(c['voltage_diff'] for c in all_cells) / len(all_cells):.3f}V")
    print(f"  심각한 불균형 건수 (>0.1V): {len(critical_imbalance)}건")
    print(f"  경고 수준 건수 (0.05~0.1V): {len(warning_imbalance)}건")

    print(f"\n[개별 셀 전압 범위]")
    for i in range(1, 9):
        cell_key = f'cell{i}'
        cell_voltages = [c[cell_key] for c in all_cells]
        print(f"  Cell {i}: {min(cell_voltages):.3f}V ~ {max(cell_voltages):.3f}V "
              f"(평균 {sum(cell_voltages)/len(cell_voltages):.3f}V)")

    # 가장 심각한 불균형 TOP 5
    print(f"\n[불균형 심각도 TOP 5]")
    top5_imbalance = sorted(all_cells, key=lambda x: x['voltage_diff'], reverse=True)[:5]
    for i, c in enumerate(top5_imbalance, 1):
        print(f"  {i}. {c['timestamp'].strftime('%Y-%m-%d %H:%M:%S')} - "
              f"불균형: {c['voltage_diff']:.3f}V "
              f"(최고 {c['max_voltage']:.3f}V - 최저 {c['min_voltage']:.3f}V)")

print("\n" + "=" * 80)
print("분석 완료!")
print("=" * 80)
