#!/usr/bin/env python3
"""
스토커 기본 데이터 문서 생성 스크립트 v2

validated_data.json (또는 intermediate_data.json)에서
03_스토커별_기본데이터_v2.md 생성
"""

import json
import sys
from pathlib import Path
from typing import Dict, List
from datetime import datetime

# config 임포트
sys.path.append(str(Path(__file__).parent))
import config

def generate_header() -> str:
    """문서 헤더 생성"""
    return f"""# 01. 분석 기초자료 (v2)

## 📌 문서 개요

본 문서는 던전 스토커즈 전투 시스템의 **기초 데이터**를 종합 정리한 자료입니다.

### 구성
1. **분석 전제조건**: 레벨, 기어스코어, 룬 빌드, 장비 스탯 추정
2. **스토커별 기본 데이터**: 10명 스토커의 스탯, 스킬, 평타 정보
3. **특수 시스템 상세**: Parrying, Chain Score, Reload, Charging 등

## 데이터 소스
- `DT_CharacterStat`: 기본 스탯, 스킬 목록
- `DT_CharacterAbility`: 평타 몽타주
- `DT_Skill`: 스킬 상세 정보 (이름, 피해배율, 쿨타임, 마나, 시전시간, 효과)
- `DT_Rune`, `DT_RuneGroup`: 룬 시스템 데이터
- `DT_Equip`, `DT_Float`: 장비 및 기어스코어 상수
- `Blueprint`: 스킬 변수 (ActivationOrderGroup 등)
- `AnimMontage`: 타이밍 및 공격 노티파이, 실제 발사 시점

## 검증 상태
- ✅ 모든 데이터는 최신 JSON에서 추출
- ✅ 교차 검증 완료
- ✅ 출처 명시 (각 데이터 필드별)

---

"""

def generate_stalker_overview(data: Dict) -> str:
    """10명 스토커 종합 비교표"""
    md = "## 10명 스토커 종합 비교표\n\n"
    md += "| 스토커 | 직업 | STR | DEX | INT | CON | WIS | 궁극기 | 장착 무기 | 평타 |\n"
    md += "|--------|------|-----|-----|-----|-----|-----|--------|-----------|------|\n"

    for stalker_id in config.STALKERS:
        if stalker_id not in data:
            continue

        stalker = data[stalker_id]
        stats = stalker['stats']
        st = stats['stats']

        # 궁극기
        has_ultimate = "⭐" if stats['ultimateSkill'] else ""

        # 장착 무기
        equip_types = ', '.join(stats['equipableTypes'])

        # 평타 콤보
        attack_map = stalker['abilities'].get('attackMontageMap', {})
        combo_counts = []
        for weapon_type, montage_data in attack_map.items():
            count = len(montage_data.get('montageArray', []))
            combo_counts.append(f"{count}타")
        combo_str = ', '.join(combo_counts) if combo_counts else "N/A"

        md += f"| **{stats['name']}** | {stats['jobName']} | {st['str']} | {st['dex']} | {st['int']} | {st['con']} | {st['wis']} | {has_ultimate} | {equip_types} | {combo_str} |\n"

    md += "\n**특징**:\n"
    md += "- **모든 스토커가 궁극기 보유**\n"
    md += "- 모든 스토커 스탯 합계: 75 포인트 (균형)\n"
    md += "- HP/MP 동일: 100/50\n"
    md += "- 마나 회복: 0.2/초 (전원 동일)\n\n"
    md += "---\n\n"

    return md

def generate_ultimate_overview(data: Dict) -> str:
    """궁극기 종합 비교"""
    md = "## 궁극기 종합 비교\n\n"
    md += "| 스토커 | 궁극기 이름 | 타입 | 피해배율 | 지속/시전 | 주요 효과 |\n"
    md += "|--------|-------------|------|----------|-----------|----------|\n"

    for stalker_id in config.STALKERS:
        if stalker_id not in data:
            continue

        stalker = data[stalker_id]
        ultimate_skill = stalker.get('ultimateSkill')

        if not ultimate_skill:
            continue

        name = ultimate_skill.get('name', 'N/A')
        skill_type = ultimate_skill.get('skillAttackType', 'Normal')
        damage_rate = ultimate_skill.get('skillDamageRate', 0)
        active_duration = ultimate_skill.get('activeDuration', 0)
        casting_time = ultimate_skill.get('castingTime', 0)

        # 설명 (descFormatted 사용 - 변수 치환 및 줄바꿈 제거됨)
        desc = ultimate_skill.get('descFormatted', ultimate_skill.get('simpleDesc', ''))[:100]

        stalker_name = stalker['stats']['name']

        md += f"| **{stalker_name}** | {name} | {skill_type} | {damage_rate} | {active_duration}초 / {casting_time}초 | {desc}... |\n"

    md += "\n---\n\n"

    return md

def generate_dot_overview(data: Dict) -> str:
    """DoT 스킬 종합 비교"""
    md = "## DoT 스킬 종합 비교\n\n"
    md += "다음 스킬들은 DoT(Damage over Time) 효과가 있으며, **DPS 계산 시 추가 지속 피해를 고려해야 합니다**.\n\n"
    md += "| 스토커 | 스킬 이름 | DoT 타입 | 기본 피해 | DoT 피해 | 지속시간 |\n"
    md += "|--------|----------|----------|----------|----------|----------|\n"

    # config.DOT_SKILLS에서 DoT 스킬 정보 가져오기
    for skill_id, dot_info in config.DOT_SKILLS.items():
        stalker_id = dot_info['stalker']
        if stalker_id not in data:
            continue

        stalker = data[stalker_id]
        stalker_name = stalker['stats']['name']
        skills = stalker.get('skills', {})

        if skill_id not in skills:
            continue

        skill = skills[skill_id]
        skill_name = skill.get('name', 'N/A')
        dot_type = dot_info.get('dot_type', 'DoT')
        damage_rate = skill.get('skillDamageRate', 0)

        # DoT 피해 설명
        if dot_type == 'Poison':
            dot_damage = "대상 MaxHP의 20%"
            duration = "5초"
        elif dot_type == 'Burn':
            dot_damage = "대상 MaxHP의 10%"
            duration = "3초"
        elif dot_type == 'Bleed':
            dot_damage = "고정 20 피해"
            duration = "5초"
        else:
            dot_damage = "N/A"
            duration = "N/A"

        md += f"| **{stalker_name}** | {skill_name} | {dot_type} | {damage_rate} | {dot_damage} | {duration} |\n"

    md += "\n**주의사항**:\n"
    md += "- DoT 피해는 대상의 HP에 비례하므로, 적의 체력에 따라 실제 피해량이 달라집니다.\n"
    md += "- 구체적인 DoT DPS 계산 방법은 다음 챕터에서 다룹니다.\n"
    md += "- 위 표의 '기본 피해'는 스킬의 skillDamageRate입니다.\n\n"
    md += "---\n\n"

    return md

def get_montage_tag(montage_name: str) -> str:
    """
    몽타주 이름에서 태그 추출

    Args:
        montage_name: 몽타주 이름

    Returns:
        태그 문자열 (예: "[준비]", "[장비]") 또는 빈 문자열
    """
    montage_tags = config.SEQUENCE_CALCULATION_RULES.get('montage_tags', {})
    exclude_keywords = config.SEQUENCE_CALCULATION_RULES.get('exclude_keywords', [])

    for keyword in exclude_keywords:
        if keyword.lower() in montage_name.lower():
            return montage_tags.get(keyword, '')

    return ''

def calculate_sequence_length(skill_id: str, montage_data: List[Dict]) -> tuple:
    """
    스킬의 시퀀스 길이 계산

    Args:
        skill_id: 스킬 ID
        montage_data: 몽타주 데이터 리스트

    Returns:
        (sequence_length, is_average, included_montages)
        - sequence_length: 계산된 시퀀스 길이
        - is_average: 평균 계산 여부
        - included_montages: 계산에 포함된 몽타주 리스트 (인덱스)
    """
    if not montage_data:
        return 0, False, []

    rules = config.SEQUENCE_CALCULATION_RULES
    exclude_keywords = rules.get('exclude_keywords', [])
    average_skills = rules.get('average_skills', [])
    exclude_montages = rules.get('exclude_montages', {})
    exclude_montage_indices = rules.get('exclude_montage_indices', {})

    # 1. 특정 몽타주 제외 리스트 가져오기
    skill_exclude_list = exclude_montages.get(skill_id, [])
    skill_exclude_indices = exclude_montage_indices.get(skill_id, [])

    # 2. 포함될 몽타주 필터링
    included_montages = []
    for idx, montage in enumerate(montage_data):
        montage_name = montage.get('assetName', '')

        # 인덱스로 제외 체크
        if idx in skill_exclude_indices:
            continue

        # 특정 몽타주 제외 체크
        if montage_name in skill_exclude_list:
            continue

        # 키워드 제외 체크 (대소문자 구분 없음)
        has_exclude_keyword = any(
            keyword.lower() in montage_name.lower()
            for keyword in exclude_keywords
        )

        if not has_exclude_keyword:
            included_montages.append(idx)

    # 3. 포함된 몽타주가 없으면 0 반환
    if not included_montages:
        return 0, False, []

    # 4. 시퀀스 길이 계산
    is_average = skill_id in average_skills

    if is_average:
        # 평균 계산
        total = sum(montage_data[idx].get('actualDuration', 0) for idx in included_montages)
        sequence_length = total / len(included_montages) if included_montages else 0
    else:
        # 합산 계산
        sequence_length = sum(montage_data[idx].get('actualDuration', 0) for idx in included_montages)

    return sequence_length, is_average, included_montages

def generate_stalker_detail(stalker_id: str, stalker_data: Dict) -> str:
    """개별 스토커 상세 정보"""
    stats = stalker_data['stats']
    st = stats['stats']
    info = config.STALKER_INFO.get(stalker_id, {})

    # stats['name']은 이미 "English (Korean)" 형식
    md = f"## {config.STALKERS.index(stalker_id) + 1}. {stats['name']} - {info.get('role', stats['jobName'])}\n\n"

    # 기본 정보
    md += "### 기본 정보\n"
    md += f"- **역할**: {info.get('role', 'N/A')}\n"
    md += f"- **주 스탯**: "

    # 주 스탯 찾기 (가장 높은 2개)
    stat_pairs = [(k.upper(), v) for k, v in st.items()]
    stat_pairs.sort(key=lambda x: x[1], reverse=True)
    md += f"{stat_pairs[0][0]} {stat_pairs[0][1]}, {stat_pairs[1][0]} {stat_pairs[1][1]}\n"

    md += f"- **HP**: {stats['hp']} | **MP**: {stats['mp']} | **마나 회복**: {stats['manaRegen']}/초\n"

    # 크리티컬 스탯
    crit_per = stats.get('criticalPer', 5)
    crit_dmg = stats.get('criticalDamage', 0)
    md += f"- **크리티컬**: 확률 {crit_per}% | 추가 피해 {crit_dmg}%\n"

    # 장착 무기
    equip_types = ', '.join(stats['equipableTypes'])
    md += f"- **장착 가능**: {equip_types}\n"

    # 평타
    attack_map = stalker_data['abilities'].get('attackMontageMap', {})
    if attack_map:
        combo_info = []
        for weapon_type, montage_data in attack_map.items():
            count = len(montage_data.get('montageArray', []))
            combo_info.append(f"{weapon_type} {count}타")
        md += f"- **평타**: {', '.join(combo_info)}\n"

    md += "\n"

    # 평타 상세 정보
    basic_attacks = stalker_data.get('basicAttacks', {})
    if basic_attacks:
        md += "### 평타 상세 정보\n\n"
        for weapon_type, attacks in basic_attacks.items():
            if attacks:
                md += f"**{weapon_type}** ({len(attacks)}타 콤보):\n\n"
                md += "| 타수 | 몽타주 | 실제 시간(초) | 배율(%) | 비고 |\n"
                md += "|------|--------|---------------|---------|------|\n"
                for attack in attacks:
                    idx = attack['index']
                    montage_name = attack['montageName']
                    # effectiveDuration 사용 (ANS_AttackState 종료 시점 우선)
                    duration = attack.get('effectiveDuration', attack['actualDuration'])
                    multiplier = attack['attackMultiplier']
                    mult_display = f"{multiplier:+.1f}" if multiplier != 0 else "0.0"

                    # 비고: ANS_AttackState 적용 여부 표시
                    notes = []
                    tag = get_montage_tag(montage_name)
                    if tag:
                        notes.append(tag)
                    if attack.get('attackStateEndTime') is not None:
                        notes.append(f"ANS_AttackState: {attack['attackStateEndTime']:.2f}초")
                    note = ", ".join(notes) if notes else ""

                    md += f"| {idx} | {montage_name} | {duration:.2f} | {mult_display} | {note} |\n"
                md += "\n"

    # 기본 스킬
    md += "### 스킬 목록\n\n"
    md += "**기본 스킬**:\n\n"

    default_skills = stalker_data.get('defaultSkills', [])
    for idx, skill in enumerate(default_skills, 1):
        if not skill:
            continue
        md += generate_skill_entry(skill, idx)

    # 서브 스킬
    sub_skill = stalker_data.get('subSkill')
    if sub_skill:
        md += "\n**서브 스킬**:\n\n"
        md += generate_skill_entry(sub_skill, 0, is_sub=True)

    # 궁극기
    ultimate_skill = stalker_data.get('ultimateSkill')
    if ultimate_skill:
        md += "\n**궁극기**:\n\n"
        md += generate_skill_entry(ultimate_skill, 0, is_ultimate=True)

    # 소환체 (레네만)
    summons = stalker_data.get('summons', {})
    if summons:
        md += "\n### 소환체\n\n"
        for summon_name, summon_data in summons.items():
            md += generate_summon_entry(summon_name, summon_data)

    md += "\n---\n\n"

    return md

def generate_summon_entry(summon_name: str, summon_data: Dict) -> str:
    """소환체 엔트리 생성"""
    summon_skill_id = summon_data.get('summonSkillId', 'N/A')
    summon_skill_name = summon_data.get('summonSkillName', 'N/A')
    active_duration = summon_data.get('activeDuration', 0)
    skill_damage_rate = summon_data.get('skillDamageRate', 0)
    attack_montages = summon_data.get('attackMontages', [])
    dot_type = summon_data.get('dotType', '')

    # 소환체 타입별 아이콘
    icon = ''
    if 'ifrit' in summon_name.lower() or '화염' in summon_skill_name:
        icon = '🔥'
    elif 'shiva' in summon_name.lower() or '냉기' in summon_skill_name or '얼음' in summon_skill_name:
        icon = '❄️'

    md = f"#### {icon} {summon_name}\n\n"
    md += f"- **소환 스킬**: {summon_skill_id} {summon_skill_name}\n"

    if active_duration > 0:
        md += f"- **소환 유지 시간**: {active_duration}초\n"

    # 공격 몽타주 정보 및 DPS 계산
    if attack_montages:
        md += f"- **공격 몽타주**: \n"

        # 공격 사이클 계산 (순차적 반복)
        total_cycle_time = 0
        montage_durations = []
        for montage in attack_montages:
            montage_name = montage.get('montageName', 'N/A')
            duration = montage.get('actualDuration', 0)
            md += f"  - {montage_name} ({duration:.2f}초)\n"
            total_cycle_time += duration
            montage_durations.append(duration)

        # 공격 사이클 및 DPS 계산
        if len(attack_montages) > 0 and total_cycle_time > 0:
            # 공격 사이클 표시
            if len(attack_montages) == 1:
                # 몽타주 1개
                md += f"- **공격 사이클**: {montage_durations[0]:.2f}초 (반복)\n"
            else:
                # 몽타주 2개 이상: 순차 표시 + 총 합계
                cycle_str = " → ".join([f"{d:.2f}초" for d in montage_durations])
                md += f"- **공격 사이클**: {cycle_str} (총 {total_cycle_time:.2f}초, 반복)\n"

            # 예상 공격 횟수 계산
            if active_duration > 0:
                cycle_count = active_duration / total_cycle_time
                attack_count = cycle_count * len(attack_montages)
                total_damage = attack_count * skill_damage_rate
                md += f"- **예상 공격 횟수**: ~{attack_count:.1f}회\n"
                md += f"- **총 피해 배율**: ~{total_damage:.2f}배 상당\n"

    if dot_type:
        dot_config = config.DOT_DAMAGE.get(dot_type, {})
        dot_desc = dot_config.get('description', f'{dot_type} DoT')
        md += f"- **특수 효과**: {dot_type} DoT ({dot_desc})\n"

    md += "\n"
    return md

def generate_skill_entry(skill: Dict, index: int, is_sub: bool = False, is_ultimate: bool = False) -> str:
    """개별 스킬 엔트리 생성"""
    skill_id = skill.get('skillId', 'N/A')
    name = skill.get('name', 'N/A')
    skill_type = skill.get('skillAttackType', 'Normal')
    element = skill.get('skillElementType', 'None')
    damage_rate = skill.get('skillDamageRate', 0)
    cooltime = skill.get('coolTime', 0)
    mana = skill.get('manaCost', 0)
    casting_time = skill.get('castingTime', 0)
    # 설명 (descFormatted 사용 - 변수 치환 및 줄바꿈 제거됨)
    desc = skill.get('descFormatted', skill.get('simpleDesc', ''))

    md = ""
    if index > 0:
        md += f"{index}. "

    md += f"**{skill_id} {name}**\n"
    md += f"   - **타입**: {skill_type}"
    if element and element != 'None':
        md += f" / **속성**: {element}"
    md += "\n"

    if damage_rate > 0:
        md += f"   - **피해 배율**: {damage_rate}\n"

    # 쿨타임, 마나, 시전시간 표시
    if cooltime > 0 or mana > 0 or casting_time > 0:
        parts = []
        if cooltime > 0:
            parts.append(f"**쿨타임**: {cooltime}초")
        if mana > 0:
            parts.append(f"**마나**: {mana}")
        if casting_time > 0:
            parts.append(f"**시전시간**: {casting_time}초")

        if parts:
            md += f"   - {' / '.join(parts)}\n"

    # 특수 마커
    is_dot = skill.get('isDot', False)
    is_summon = skill.get('isSummon', False)
    is_utility = skill.get('isUtility', False)

    # 유틸리티 스킬 표시
    if is_utility:
        md += f"   - 💡 **유틸리티 스킬** (DPS 계산 제외)\n"

    if is_dot:
        dot_info = config.DOT_SKILLS.get(skill_id, {})
        dot_type = dot_info.get('dot_type', 'DoT')

        # DoT 피해 상세 정보
        if dot_type == 'Poison':
            dot_detail = "대상 MaxHP의 20% (5초간)"
        elif dot_type == 'Burn':
            dot_detail = "대상 MaxHP의 10% (3초간)"
        elif dot_type == 'Bleed':
            dot_detail = "고정 20 피해 (5초간)"
        else:
            dot_detail = "지속 피해"

        md += f"   - ⚠️  **{dot_type} 상태이상 유발**: {dot_detail}\n"
        md += f"   - 💡 **DoT 피해는 대상 HP에 비례** (구체적 DPS는 다음 챕터 참조)\n"

    if is_summon:
        summon_info = config.SUMMON_SKILLS.get(skill_id, {})
        summon_name = summon_info.get('summon', 'Summon')
        duration = skill.get('activeDuration', 0)
        md += f"   - 🔮 **소환**: {summon_name} (지속 {duration}초)\n"

    # 몽타주 정보 표시 (이름 + 시간 + 태그)
    montage_data = skill.get('montageData', [])
    if montage_data:
        if len(montage_data) == 1:
            # 몽타주 1개: 한 줄로 표시
            montage = montage_data[0]
            montage_name = montage.get('assetName', 'N/A')
            tag = get_montage_tag(montage_name)
            tag_display = f" {tag}" if tag else ""
            md += f"   - **몽타주**: {montage_name}{tag_display}\n"
        else:
            # 몽타주 여러 개: 리스트로 표시
            md += f"   - **몽타주**: \n"
            for idx, montage in enumerate(montage_data, 1):
                montage_name = montage.get('assetName', 'N/A')
                duration = montage.get('actualDuration', 0)
                tag = get_montage_tag(montage_name)
                tag_display = f" {tag}" if tag else ""
                md += f"     {idx}. {montage_name} ({duration:.2f}초){tag_display}\n"

        # 시퀀스 길이 (새로운 계산 규칙 적용)
        sequence_length, is_average, included_montages = calculate_sequence_length(skill_id, montage_data)
        if sequence_length > 0 or len(montage_data) > 0:
            # 평균 표시 추가
            avg_text = " (평균)" if is_average else ""
            md += f"   - **시퀀스 길이**: {sequence_length:.2f}초{avg_text}\n"

    # 설명 (전체 표시)
    if desc:
        md += f"   - **설명**: {desc}\n"

    md += "\n"

    return md

def generate_analysis_prerequisites(data: Dict) -> str:
    """분석 전제조건 섹션 생성"""
    md = "## 📋 분석 전제조건\n\n"

    # 공통 설정
    md += "### 기본 설정\n"
    md += f"- **레벨**: {config.ANALYSIS_BASELINE['level']}\n"
    md += f"- **기어 스코어**: {config.ANALYSIS_BASELINE['gear_score']}\n"
    md += f"- **플레이 스타일**: {config.ANALYSIS_BASELINE['play_style']}\n\n"

    # 장비 스탯 추정 (metadata에서 추출)
    md += "### 장비 스탯 추정 (기어스코어 400 기준)\n\n"
    metadata = data.get('_metadata', {})
    gear_constants = metadata.get('gearScoreConstants', {})

    md += "**무기** (레벨 20, Rare 등급 기준):\n"
    md += "- PhysicalDamage: +65\n"
    md += "- MagicalDamage: +65\n\n"

    md += "**방어구 3부위** (갑옷, 다리, 액세서리):\n"
    md += "- 총 PhysicalDamage: +15\n"
    md += "- 총 MagicalDamage: +15\n"
    md += "- HP: +120\n"
    md += "- Defense: +80\n\n"

    md += "**총 장비 보너스**:\n"
    md += "- PhysicalDamage: +80\n"
    md += "- MagicalDamage: +80\n"
    md += "- HP: +120\n"
    md += "- Defense: +80\n\n"

    # 룬 빌드 설정 (metadata에서 룬 데이터 활용)
    md += "### 역할별 최적 룬 빌드\n\n"
    runes = metadata.get('runes', {})
    rune_groups = metadata.get('runeGroups', {})

    # 물리 딜러 빌드 예시 (룬 데이터에서 추출)
    md += "#### 물리 딜러 (Hilda, Baran, Rio, Sinobu, Cazimord)\n\n"
    md += "**Main: 스킬 그룹 (20xxx)**\n"
    md += "- 20101 저주 (조건부 지연 피해)\n"
    md += "- 20201 파괴 (+10% 스킬 피해)\n"
    md += "- 20301 명상 (+70% 마나 회복)\n\n"
    md += "**Sub: 전투 그룹 (10xxx)**\n"
    md += "- 10201 분노 (+10% 물리 피해)\n"
    md += "- 10103 공략 (+20% 머리 공격 피해)\n\n"

    md += "#### 마법 딜러 (Nave, Rene)\n\n"
    md += "**Main: 스킬 그룹 (20xxx)**\n"
    md += "- 20103 활기 (마나 높을 때 스킬 피해 증가)\n"
    md += "- 20202 왜곡 (-25% 쿨타임)\n"
    md += "- 20301 명상 (+70% 마나 회복)\n\n"
    md += "**Sub: 전투 그룹 (10xxx)**\n"
    md += "- 10301 폭풍 (+10% 마법 피해)\n"
    md += "- 10103 공략 (+20% 머리 공격 피해)\n\n"

    md += "#### 원거리 딜러 (Urud, Lian)\n\n"
    md += "**Main: 스킬 그룹 (20xxx)**\n"
    md += "- 20101 저주 (지연 피해)\n"
    md += "- 20201 파괴 (+10% 스킬 피해)\n"
    md += "- 20301 명상 (+70% 마나 회복)\n\n"
    md += "**Sub: 전투 그룹 (10xxx)**\n"
    md += "- 10201 분노 (+10% 물리 피해)\n"
    md += "- 10103 공략 (+20% 머리 공격 피해)\n\n"

    md += "#### 서포터 (Clad)\n\n"
    md += "**Main: 전투 그룹 (10xxx)**\n"
    md += "- 10101 충전 (+30% 궁극기 회복)\n"
    md += "- 10202 방패 (+7% 물리 저항)\n"
    md += "- 10302 수호 (+7% 마법 저항)\n\n"
    md += "**Sub: 보조 그룹 (40xxx)**\n"
    md += "- 40201 면역 (물약 사용 시 +20% 저항 20초)\n"
    md += "- 40301 효율 (+50% 물약 효과)\n\n"

    # 특수 시스템 활용률
    md += "### 특수 시스템 활용률\n\n"
    md += "**전제**: 최적 플레이 = 100% 활용\n\n"

    md += "#### Cazimord - Parrying (흘리기)\n"
    md += "- **판정 윈도우**: 0.2초\n"
    md += "- **성공 시 효과**:\n"
    md += "  - 적 피해 무효화\n"
    md += "  - 자동 반격 (높은 피해)\n"
    md += "  - **스킬 쿨타임 감소**:\n"
    md += "    - 섬광(SK170201): -3.8초\n"
    md += "    - 날개베기(SK170202): -3.8초\n"
    md += "    - 작열(SK170203): -6.8초\n"
    md += "- **활용률 시나리오**: 0% (미사용) vs 100% (완벽 성공)\n\n"

    md += "#### Rio - Chain Score\n"
    md += "- **최대 스택**: 3\n"
    md += "- **효과**: 각 스킬별로 다른 위력 증가\n"
    md += "- **충전**: Dropping Attack 성공 시\n"
    md += "- **활용률**: 100% (항상 3스택 유지)\n\n"

    md += "#### Urud & Lian - Reload\n"
    md += "- **탄약**: 6발\n"
    md += "- **재장전 시간**: 2.0초\n"
    md += "- **활용률**: 100% (탄약 관리 최적화)\n\n"

    md += "#### Lian - Charging Bow\n"
    md += "- **만충전 데미지**: 1.5배\n"
    md += "- **충전 시간**: 레벨당 0.5초 (최대 1.5초)\n"
    md += "- **활용률**: 100% (항상 만충전 후 발사)\n\n"

    md += "#### Rene - Spirit 소환\n"
    md += "- **소환수**: Ifrit, Shiva\n"
    md += "- **활용률**: 100% (소환수 항상 활용)\n\n"

    md += "#### Sinobu - Shuriken 충전\n"
    md += "- **최대 충전**: 3개\n"
    md += "- **충전 속도**: 1초/개\n"
    md += "- **활용률**: 100% (충전 관리 최적화)\n\n"

    md += "---\n\n"

    return md

def generate_special_systems(data: Dict) -> str:
    """특수 시스템 상세 분석 섹션 생성"""
    md = "## 🔧 특수 시스템 상세\n\n"

    md += "### Cazimord - Parrying (흘리기)\n\n"
    md += "#### 메커니즘\n"
    md += "- **판정 윈도우**: 0.2초\n"
    md += "- **패링 성공 시**:\n"
    md += "  - 적 공격 무효화\n"
    md += "  - 자동 반격 (높은 피해)\n"
    md += "  - 스킬 쿨타임 감소\n\n"

    md += "#### 쿨타임 감소 효과\n"
    md += "| 스킬 | 기본 쿨타임 | 패링 성공 시 감소 | 패링 100% 시 유효 쿨타임 |\n"
    md += "|------|-------------|-------------------|------------------------|\n"

    # Cazimord 스킬 데이터에서 쿨타임 정보 추출
    if 'cazimord' in data:
        cazimord = data['cazimord']
        skills = cazimord.get('skills', {})

        parrying_skills = {
            'SK170201': ('섬광', -3.8),
            'SK170202': ('날개베기', -3.8),
            'SK170203': ('작열', -6.8)
        }

        for skill_id, (skill_name, reduction) in parrying_skills.items():
            if skill_id in skills:
                skill = skills[skill_id]
                base_cooltime = skill.get('coolTime', 0)
                effective_cooltime = max(0, base_cooltime + reduction)
                md += f"| {skill_name} | {base_cooltime:.1f}초 | {reduction}초 | {effective_cooltime:.1f}초 |\n"

    md += "\n#### DPS 영향\n"
    md += "- **패링 0%**: 기본 쿨타임 적용\n"
    md += "- **패링 100%**: 쿨타임 감소로 스킬 회전율 증가 → DPS 상승\n\n"

    md += "### Rio - Chain Score\n\n"
    md += "#### 메커니즘\n"
    md += "- **스택 시스템**: 최대 3스택\n"
    md += "- **스택 획득**: Dropping Attack 스킬 성공 시 +1\n"
    md += "- **효과**: 스킬별로 스택 소모 및 추가 효과 발동\n\n"

    md += "#### 스택별 효과\n"
    md += "- 각 스킬이 Chain Score 스택을 소모하여 강화\n"
    md += "- 스킬마다 다른 위력 증가 배율 적용\n\n"

    md += "### Urud & Lian - Reload 시스템\n\n"
    md += "#### 메커니즘\n"
    md += "- **최대 탄약**: 6발\n"
    md += "- **재장전 시간**: 2.0초\n"
    md += "- **재장전 중**: 다른 행동 불가 (DPS 손실)\n\n"

    md += "#### DPS 영향\n"
    md += "- 6발 소진 후 2초 공백 발생\n"
    md += "- 최적 플레이: 탄약 관리로 전투 공백 최소화\n\n"

    md += "### Lian - Charging Bow\n\n"
    md += "#### 메커니즘\n"
    md += "- **충전 단계**: 3단계 (0.5초씩)\n"
    md += "- **만충전 배율**: 1.5배\n"
    md += "- **충전 중**: 이동 속도 감소\n\n"

    md += "#### DPS 영향\n"
    md += "- 만충전 시 피해량 증가\n"
    md += "- 충전 시간 vs 피해량 트레이드오프\n\n"

    md += "### Rene - 소환수 시스템\n\n"
    md += "#### Ifrit (화염 정령)\n"
    if 'rene' in data:
        rene = data['rene']
        summons = rene.get('summons', {})
        if 'Ifrit' in summons:
            ifrit = summons['Ifrit']
            md += f"- **지속 시간**: {ifrit.get('activeDuration', 0)}초\n"
            md += f"- **공격 타입**: 근접 화염 공격\n"
            md += f"- **독립 DPS**: 계산 필요 (소환수 몽타주 기반)\n\n"

    md += "#### Shiva (냉기 정령)\n"
    if 'rene' in data and 'Shiva' in rene.get('summons', {}):
        shiva = summons.get('Shiva', {})
        md += f"- **지속 시간**: {shiva.get('activeDuration', 0)}초\n"
        md += f"- **공격 타입**: 원거리 냉기 공격\n"
        md += f"- **독립 DPS**: 계산 필요 (소환수 몽타주 기반)\n\n"

    md += "### Sinobu - Shuriken 충전\n\n"
    md += "#### 메커니즘\n"
    md += "- **최대 충전**: 3개\n"
    md += "- **충전 속도**: 1초/개 (자동)\n"
    md += "- **소모**: 특정 스킬 사용 시 1개씩 소모\n\n"

    md += "#### DPS 영향\n"
    md += "- 충전 관리로 스킬 사용 빈도 조절\n"
    md += "- 최적 플레이: 충전 타이밍 고려한 스킬 로테이션\n\n"

    md += "---\n\n"

    return md

def main():
    """메인 실행 함수"""
    print("="*80)
    print("스토커 기본 데이터 문서 생성 v2")
    print("="*80)

    # 검증된 데이터 로드 (없으면 intermediate 사용)
    validated_file = config.OUTPUT_DIR / "validated_data.json"
    intermediate_file = config.OUTPUT_DIR / "intermediate_data.json"

    if validated_file.exists():
        data_file = validated_file
        print(f"\n[ 검증된 데이터 사용 ]: {data_file}")
    elif intermediate_file.exists():
        data_file = intermediate_file
        print(f"\n[ 중간 데이터 사용 ]: {data_file}")
        print("[WARN] 검증되지 않은 데이터입니다. validate_stalker_data.py를 먼저 실행하는 것을 권장합니다.")
    else:
        print(f"[FAIL] 데이터 파일 없음")
        print("먼저 extract_stalker_data_v2.py를 실행하세요.")
        return

    with open(data_file, 'r', encoding='utf-8') as f:
        data = json.load(f)

    print("\n[ 문서 생성 시작 ]")

    # 마크다운 생성
    md_content = generate_header()
    md_content += generate_analysis_prerequisites(data)  # 분석 전제조건 추가
    md_content += generate_stalker_overview(data)
    md_content += generate_ultimate_overview(data)
    md_content += generate_dot_overview(data)  # DoT 스킬 종합

    # 개별 스토커
    stalker_count = 0
    for stalker_id in config.STALKERS:
        if stalker_id not in data:
            print(f"[WARN] {stalker_id}: 데이터 없음, 건너뜀")
            continue

        print(f"  - {stalker_id} 문서 생성 중...")
        md_content += generate_stalker_detail(stalker_id, data[stalker_id])
        stalker_count += 1

    # 특수 시스템 상세 추가
    md_content += generate_special_systems(data)

    # Footer
    md_content += "---\n\n"
    md_content += f"**생성 일시**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
    md_content += f"**데이터 소스**: {data_file.name}\n"
    md_content += f"**검증 상태**: {'검증 완료' if data_file.name == 'validated_data.json' else '미검증'}\n"

    # 파일 저장 - 새 파일명 사용
    output_file = config.OUTPUT_DIR / "01_분석_기초자료_v2.md"
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(md_content)

    print(f"\n[OK] 문서 생성 완료: {output_file}")
    print(f"   - 총 {stalker_count}명 스토커 문서 생성")
    print(f"   - 분석 전제조건 포함")
    print(f"   - 특수 시스템 상세 포함")

if __name__ == "__main__":
    main()
