# -*- coding: utf-8 -*-
"""
HWP 스타일 매핑 모듈 v2.0
HTML 역할(Role) → HWP 스타일 매핑

✅ v2.0 변경사항:
- pyhwpx API에 맞게 apply_to_hwp() 재작성
- CharShape/ParaShape 직접 설정 방식
- 역할 → 개요 스타일 매핑
"""

from dataclasses import dataclass
from typing import Dict, Optional
from enum import Enum


class HwpStyleType(Enum):
    """HWP 스타일 유형"""
    PARAGRAPH = "paragraph"
    CHARACTER = "character"


@dataclass
class HwpStyle:
    """HWP 스타일 정의"""
    id: int
    name: str
    type: HwpStyleType
    font_size: float
    font_bold: bool = False
    font_color: str = "000000"
    align: str = "justify"
    line_spacing: float = 160
    space_before: float = 0
    space_after: float = 0
    indent_left: float = 0
    indent_first: float = 0
    bg_color: Optional[str] = None


# =============================================================================
# 기본 스타일 템플릿
# =============================================================================
DEFAULT_STYLES: Dict[str, HwpStyle] = {
    # 표지
    "COVER_TITLE": HwpStyle(
        id=100, name="표지제목", type=HwpStyleType.PARAGRAPH,
        font_size=32, font_bold=True, align="center",
        space_before=20, space_after=10, font_color="1a365d"
    ),
    "COVER_SUBTITLE": HwpStyle(
        id=101, name="표지부제", type=HwpStyleType.PARAGRAPH,
        font_size=18, font_bold=False, align="center",
        font_color="555555"
    ),
    "COVER_INFO": HwpStyle(
        id=102, name="표지정보", type=HwpStyleType.PARAGRAPH,
        font_size=12, align="center", font_color="666666"
    ),
    
    # 목차
    "TOC_H1": HwpStyle(
        id=110, name="목차1수준", type=HwpStyleType.PARAGRAPH,
        font_size=12, font_bold=True, indent_left=0
    ),
    "TOC_H2": HwpStyle(
        id=111, name="목차2수준", type=HwpStyleType.PARAGRAPH,
        font_size=11, indent_left=20
    ),
    "TOC_H3": HwpStyle(
        id=112, name="목차3수준", type=HwpStyleType.PARAGRAPH,
        font_size=10, indent_left=40, font_color="666666"
    ),
    
    # 제목 계층 (개요 1~7 매핑)
    "H1": HwpStyle(
        id=1, name="개요 1", type=HwpStyleType.PARAGRAPH,
        font_size=20, font_bold=True, align="left",
        space_before=30, space_after=15, font_color="1a365d"
    ),
    "H2": HwpStyle(
        id=2, name="개요 2", type=HwpStyleType.PARAGRAPH,
        font_size=16, font_bold=True, align="left",
        space_before=20, space_after=10, font_color="2c5282"
    ),
    "H3": HwpStyle(
        id=3, name="개요 3", type=HwpStyleType.PARAGRAPH,
        font_size=14, font_bold=True, align="left",
        space_before=15, space_after=8, font_color="2b6cb0"
    ),
    "H4": HwpStyle(
        id=4, name="개요 4", type=HwpStyleType.PARAGRAPH,
        font_size=12, font_bold=True, align="left",
        space_before=10, space_after=5, indent_left=10
    ),
    "H5": HwpStyle(
        id=5, name="개요 5", type=HwpStyleType.PARAGRAPH,
        font_size=11, font_bold=True, align="left",
        space_before=8, space_after=4, indent_left=20
    ),
    "H6": HwpStyle(
        id=6, name="개요 6", type=HwpStyleType.PARAGRAPH,
        font_size=11, font_bold=False, align="left",
        indent_left=30
    ),
    "H7": HwpStyle(
        id=7, name="개요 7", type=HwpStyleType.PARAGRAPH,
        font_size=10.5, font_bold=False, align="left",
        indent_left=40
    ),
    
    # 본문
    "BODY": HwpStyle(
        id=20, name="바탕글", type=HwpStyleType.PARAGRAPH,
        font_size=11, align="justify",
        line_spacing=180, indent_first=10
    ),
    "LIST_ITEM": HwpStyle(
        id=8, name="개요 8", type=HwpStyleType.PARAGRAPH,
        font_size=11, align="left",
        indent_left=15, line_spacing=160
    ),
    "HIGHLIGHT_BOX": HwpStyle(
        id=21, name="강조박스", type=HwpStyleType.PARAGRAPH,
        font_size=10.5, align="left",
        bg_color="f7fafc", indent_left=10, indent_first=0
    ),
    
    # 표
    "TABLE": HwpStyle(
        id=30, name="표", type=HwpStyleType.PARAGRAPH,
        font_size=10, align="center"
    ),
    "TH": HwpStyle(
        id=11, name="표제목", type=HwpStyleType.PARAGRAPH,
        font_size=10, font_bold=True, align="center",
        bg_color="e2e8f0"
    ),
    "TD": HwpStyle(
        id=31, name="표내용", type=HwpStyleType.PARAGRAPH,
        font_size=10, align="left"
    ),
    "TABLE_CAPTION": HwpStyle(
        id=19, name="표캡션", type=HwpStyleType.PARAGRAPH,
        font_size=10, font_bold=True, align="center",
        space_before=5, space_after=3
    ),
    
    # 그림
    "FIGURE": HwpStyle(
        id=32, name="그림", type=HwpStyleType.PARAGRAPH,
        font_size=10, align="center"
    ),
    "FIGURE_CAPTION": HwpStyle(
        id=18, name="그림캡션", type=HwpStyleType.PARAGRAPH,
        font_size=9.5, align="center",
        font_color="666666", space_before=5
    ),
    
    # 기타
    "UNKNOWN": HwpStyle(
        id=0, name="바탕글", type=HwpStyleType.PARAGRAPH,
        font_size=10, align="left"
    ),
}

# 역할 → 개요 번호 매핑 (StyleShortcut 용)
ROLE_TO_OUTLINE_NUM = {
    "H1": 1,
    "H2": 2,
    "H3": 3,
    "H4": 4,
    "H5": 5,
    "H6": 6,
    "H7": 7,
    "LIST_ITEM": 8,
    "BODY": 0,  # 바탕글
    "COVER_TITLE": 0,
    "COVER_SUBTITLE": 0,
    "COVER_INFO": 0,
}

# 역할 → HWP 스타일 이름 매핑
ROLE_TO_STYLE_NAME = {
    "H1": "개요 1",
    "H2": "개요 2",
    "H3": "개요 3",
    "H4": "개요 4",
    "H5": "개요 5",
    "H6": "개요 6",
    "H7": "개요 7",
    "LIST_ITEM": "개요 8",
    "BODY": "바탕글",
    "COVER_TITLE": "표지제목",
    "COVER_SUBTITLE": "표지부제",
    "TH": "표제목",
    "TD": "표내용",
    "TABLE_CAPTION": "표캡션",
    "FIGURE_CAPTION": "그림캡션",
    "UNKNOWN": "바탕글",
}


class HwpStyleMapper:
    """HTML 역할 → HWP 스타일 매퍼"""
    
    def __init__(self, custom_styles: Optional[Dict[str, HwpStyle]] = None):
        self.styles = DEFAULT_STYLES.copy()
        if custom_styles:
            self.styles.update(custom_styles)
    
    def get_style(self, role: str) -> HwpStyle:
        return self.styles.get(role, self.styles["UNKNOWN"])
    
    def get_style_id(self, role: str) -> int:
        return self.get_style(role).id
    
    def get_all_styles(self) -> Dict[str, HwpStyle]:
        return self.styles


class HwpStyGenerator:
    """
    HTML 스타일 → HWP 스타일 적용기
    
    pyhwpx API를 사용하여:
    1. 역할별 스타일 정보 저장
    2. 텍스트 삽입 시 CharShape/ParaShape 직접 적용
    3. 개요 스타일 번호 매핑 반환
    """
    
    def __init__(self):
        self.styles: Dict[str, HwpStyle] = {}
        self.hwp = None
    
    def update_from_html(self, html_styles: Dict[str, Dict]):
        """HTML에서 추출한 스타일로 업데이트"""
        for role, style_dict in html_styles.items():
            if role in DEFAULT_STYLES:
                base = DEFAULT_STYLES[role]
                
                # color 처리 - # 제거
                color = style_dict.get('color', base.font_color)
                if isinstance(color, str):
                    color = color.lstrip('#')
                
                self.styles[role] = HwpStyle(
                    id=base.id,
                    name=base.name,
                    type=base.type,
                    font_size=style_dict.get('font_size', base.font_size),
                    font_bold=style_dict.get('bold', base.font_bold),
                    font_color=color,
                    align=style_dict.get('align', base.align),
                    line_spacing=style_dict.get('line_spacing', base.line_spacing),
                    space_before=style_dict.get('space_before', base.space_before),
                    space_after=style_dict.get('space_after', base.space_after),
                    indent_left=style_dict.get('indent_left', base.indent_left),
                    indent_first=style_dict.get('indent_first', base.indent_first),
                    bg_color=style_dict.get('bg_color', base.bg_color),
                )
            else:
                # 기본 스타일 사용
                self.styles[role] = DEFAULT_STYLES.get('UNKNOWN')
        
        # 누락된 역할은 기본값으로 채움
        for role in DEFAULT_STYLES:
            if role not in self.styles:
                self.styles[role] = DEFAULT_STYLES[role]
    
    def apply_to_hwp(self, hwp) -> Dict[str, HwpStyle]:
        """역할 → HwpStyle 매핑 반환"""
        self.hwp = hwp
        
        # 🚫 스타일 생성 비활성화 (API 문제)
        # for role, style in self.styles.items():
        #     self._create_or_update_style(hwp, role, style)
        
        if not self.styles:
            self.styles = DEFAULT_STYLES.copy()
        
        print(f"  ✅ 스타일 매핑 완료: {len(self.styles)}개")
        return self.styles

    def _create_or_update_style(self, hwp, role: str, style: HwpStyle):
        """HWP에 스타일 생성 또는 수정"""
        try:
            # 1. 스타일 편집 모드
            hwp.HAction.GetDefault("ModifyStyle", hwp.HParameterSet.HStyle.HSet)
            hwp.HParameterSet.HStyle.StyleName = style.name
            
            # 2. 글자 모양
            color_hex = style.font_color.lstrip('#')
            if len(color_hex) == 6:
                r, g, b = int(color_hex[0:2], 16), int(color_hex[2:4], 16), int(color_hex[4:6], 16)
                text_color = hwp.RGBColor(r, g, b)
            else:
                text_color = hwp.RGBColor(0, 0, 0)
            
            hwp.HParameterSet.HStyle.CharShape.Height = hwp.PointToHwpUnit(style.font_size)
            hwp.HParameterSet.HStyle.CharShape.Bold = style.font_bold
            hwp.HParameterSet.HStyle.CharShape.TextColor = text_color
            
            # 3. 문단 모양
            align_map = {'left': 0, 'center': 1, 'right': 2, 'justify': 3}
            hwp.HParameterSet.HStyle.ParaShape.Align = align_map.get(style.align, 3)
            hwp.HParameterSet.HStyle.ParaShape.LineSpacing = int(style.line_spacing)
            hwp.HParameterSet.HStyle.ParaShape.SpaceBeforePara = hwp.PointToHwpUnit(style.space_before)
            hwp.HParameterSet.HStyle.ParaShape.SpaceAfterPara = hwp.PointToHwpUnit(style.space_after)
            
            # 4. 실행
            hwp.HAction.Execute("ModifyStyle", hwp.HParameterSet.HStyle.HSet)
            print(f"    ✓ 스타일 '{style.name}' 정의됨")
            
        except Exception as e:
            print(f"    [경고] 스타일 '{style.name}' 생성 실패: {e}")
        
    def get_style(self, role: str) -> HwpStyle:
        """역할에 해당하는 스타일 반환"""
        return self.styles.get(role, DEFAULT_STYLES.get('UNKNOWN'))
    
    def apply_char_shape(self, hwp, role: str):
        """현재 선택 영역에 글자 모양 적용"""
        style = self.get_style(role)
        
        try:
            # RGB 색상 변환
            color_hex = style.font_color.lstrip('#') if style.font_color else '000000'
            if len(color_hex) == 6:
                r = int(color_hex[0:2], 16)
                g = int(color_hex[2:4], 16)
                b = int(color_hex[4:6], 16)
                text_color = hwp.RGBColor(r, g, b)
            else:
                text_color = hwp.RGBColor(0, 0, 0)
            
            # 글자 모양 설정
            hwp.HAction.GetDefault("CharShape", hwp.HParameterSet.HCharShape.HSet)
            hwp.HParameterSet.HCharShape.Height = hwp.PointToHwpUnit(style.font_size)
            hwp.HParameterSet.HCharShape.Bold = style.font_bold
            hwp.HParameterSet.HCharShape.TextColor = text_color
            hwp.HAction.Execute("CharShape", hwp.HParameterSet.HCharShape.HSet)
            
        except Exception as e:
            print(f"    [경고] 글자 모양 적용 실패 ({role}): {e}")
    
    def apply_para_shape(self, hwp, role: str):
        """현재 문단에 문단 모양 적용"""
        style = self.get_style(role)
        
        try:
            # 정렬
            align_actions = {
                'left': "ParagraphShapeAlignLeft",
                'center': "ParagraphShapeAlignCenter",
                'right': "ParagraphShapeAlignRight",
                'justify': "ParagraphShapeAlignJustify"
            }
            if style.align in align_actions:
                hwp.HAction.Run(align_actions[style.align])
            
            # 문단 모양 상세 설정
            hwp.HAction.GetDefault("ParagraphShape", hwp.HParameterSet.HParaShape.HSet)
            p = hwp.HParameterSet.HParaShape
            p.LineSpaceType = 0  # 퍼센트
            p.LineSpacing = int(style.line_spacing)
            p.LeftMargin = hwp.MiliToHwpUnit(style.indent_left)
            p.IndentMargin = hwp.MiliToHwpUnit(style.indent_first)
            p.SpaceBeforePara = hwp.PointToHwpUnit(style.space_before)
            p.SpaceAfterPara = hwp.PointToHwpUnit(style.space_after)
            hwp.HAction.Execute("ParagraphShape", p.HSet)
            
        except Exception as e:
            print(f"    [경고] 문단 모양 적용 실패 ({role}): {e}")
    
    def apply_style(self, hwp, role: str):
        """역할에 맞는 전체 스타일 적용 (글자 + 문단)"""
        self.apply_char_shape(hwp, role)
        self.apply_para_shape(hwp, role)
    
    def export_sty(self, hwp, output_path: str) -> bool:
        """스타일 파일 내보내기 (현재 미지원)"""
        print(f"  [알림] .sty 내보내기는 현재 미지원")
        return False


# =============================================================================
# 번호 제거 유틸리티
# =============================================================================
import re

NUMBERING_PATTERNS = {
    'H1': re.compile(r'^(\d+)\.\s*'),           # "1. " → ""
    'H2': re.compile(r'^(\d+)\.(\d+)\s*'),      # "1.1 " → ""
    'H3': re.compile(r'^(\d+)\.(\d+)\.(\d+)\s*'), # "1.1.1 " → ""
    'H4': re.compile(r'^[가-하]\.\s*'),          # "가. " → ""
    'H5': re.compile(r'^(\d+)\)\s*'),           # "1) " → ""
    'H6': re.compile(r'^\((\d+)\)\s*'),         # "(1) " → ""
    'H7': re.compile(r'^[①②③④⑤⑥⑦⑧⑨⑩]\s*'),  # "① " → ""
    'LIST_ITEM': re.compile(r'^[•\-○]\s*'),    # "• " → ""
}

def strip_numbering(text: str, role: str) -> str:
    """
    역할에 따라 텍스트 앞의 번호/기호 제거
    HWP 개요 기능이 번호를 자동 생성하므로 중복 방지
    """
    if not text:
        return text
    
    pattern = NUMBERING_PATTERNS.get(role)
    if pattern:
        return pattern.sub('', text).strip()
    
    return text.strip()


if __name__ == "__main__":
    # 테스트
    print("=== 스타일 매핑 테스트 ===")
    
    gen = HwpStyGenerator()
    
    # HTML 스타일 시뮬레이션
    html_styles = {
        'H1': {'font_size': 20, 'color': '#1a365d', 'bold': True},
        'H2': {'font_size': 16, 'color': '#2c5282', 'bold': True},
        'BODY': {'font_size': 11, 'align': 'justify'},
    }
    
    gen.update_from_html(html_styles)
    
    for role, style in gen.styles.items():
        print(f"{role:15} → size={style.font_size}pt, bold={style.font_bold}, color=#{style.font_color}")