#!/usr/bin/env python3
"""나머지 22개 파일(15개 복원 + 7개 cell/m1) 마이그레이션.

3가지 유형:
  Type F: f-string 템플릿 (return f-triple-quote) - 값 치환만
  Type A: .format() 호환 (double-brace CSS) - f 접두사 + bg_url 이스케이프
  Type B: raw string (single-brace CSS) - 중괄호 이중화 + f 접두사
"""
import re
import ast
import sys
from pathlib import Path

DIR = Path(__file__).parent
FONT_PATH_HARD = "file:///home/jay/.local/share/fonts/Pretendard"
WORKSPACE_HARD = "/home/jay/workspace/"

# ── DQ 규칙 매핑 ──
DQ_SIZE_MAP = {
    40: ("_CTA_PX", "CTA_MIN_PX"),
    64: ("_SUBHEAD_PX", "SUBHEAD_MIN_PX"),
    84: ("_HEADLINE_PX", "HEADLINE_MIN_PX"),
    96: ("_METRIC_PX", "CORE_METRIC_MIN_PX"),
}

LH_RATIO_MAP = {
    "1.3": ("_LH_RATIO", "HEAD_SUB_RATIO"),
}


def var_name_for_size(px):
    if px in DQ_SIZE_MAP:
        return DQ_SIZE_MAP[px][0]
    return f"_SIZE_{px}PX"


def var_def_for_size(px):
    if px in DQ_SIZE_MAP:
        return f"{DQ_SIZE_MAP[px][0]} = {DQ_SIZE_MAP[px][1]}"
    return f"_SIZE_{px}PX = {px}"


def var_name_for_lh(kind, val):
    if kind == "px":
        return f"_LH_{val}PX"
    if str(val) in LH_RATIO_MAP:
        return LH_RATIO_MAP[str(val)][0]
    safe = str(val).replace(".", "_")
    return f"_LH_{safe}"


def var_def_for_lh(kind, val):
    if kind == "px":
        return f"_LH_{val}PX = {val}"
    if str(val) in LH_RATIO_MAP:
        name, ref = LH_RATIO_MAP[str(val)]
        return f"{name} = {ref}"
    safe = str(val).replace(".", "_")
    return f"_LH_{safe} = {val}"


def collect_values(source):
    """파일에서 font-size/line-height 값 수집."""
    sizes = set()
    lh_dict = {}
    for m in re.finditer(r'font-size:\s*(\d+)px', source):
        sizes.add(int(m.group(1)))
    for m in re.finditer(r'line-height:\s*(\d+)px', source):
        lh_dict[f"line-height: {m.group(1)}px"] = ("px", int(m.group(1)))
    for m in re.finditer(r'line-height:\s*(\d+\.\d+)', source):
        if "px" not in m.group(0):
            lh_dict[f"line-height: {m.group(1)}"] = ("ratio", m.group(1))
    return sizes, lh_dict


def build_imports_and_defs(sizes, lh_dict, has_font_path, has_workspace_path):
    """Import 심볼 목록과 변수 정의 생성."""
    symbols = set()
    if has_workspace_path:
        symbols.add("WORKSPACE_ROOT")
    if has_font_path:
        symbols.add("FONT_DIR")

    defs = []
    for px in sorted(sizes):
        if px in DQ_SIZE_MAP:
            symbols.add(DQ_SIZE_MAP[px][1])
        defs.append(var_def_for_size(px))

    seen = set()
    for _, (kind, val) in sorted(lh_dict.items(), key=lambda x: str(x[1])):
        if kind == "ratio" and str(val) in LH_RATIO_MAP:
            symbols.add(LH_RATIO_MAP[str(val)][1])
        d = var_def_for_lh(kind, val)
        name = d.split("=")[0].strip()
        if name not in seen:
            seen.add(name)
            defs.append(d)

    # Deduplicate size defs too
    final_defs = []
    seen2 = set()
    for d in defs:
        name = d.split("=")[0].strip()
        if name not in seen2:
            seen2.add(name)
            final_defs.append(d)

    return sorted(symbols), final_defs


def insert_imports_at_top(source, symbols, var_defs):
    """TOP-LEVEL import 뒤에 삽입 (들여쓰기된 import 무시)."""
    if not symbols:
        return source

    import_line = f"from gen_config import {', '.join(symbols)}"
    lines = source.split('\n')
    insert_idx = 0

    for i, line in enumerate(lines):
        # Only top-level (non-indented) lines
        if not line or (line[0] == ' ' or line[0] == '\t'):
            continue
        stripped = line.strip()
        if stripped.startswith('import ') or stripped.startswith('from '):
            insert_idx = i + 1
        elif stripped.startswith('sys.path.insert'):
            insert_idx = i + 1

    block = [import_line, ""]
    if var_defs:
        block.append("# ── 디자인 토큰 ──")
        block.extend(var_defs)
        block.append("")

    lines[insert_idx:insert_idx] = block
    return '\n'.join(lines)


def replace_font_sizes(source, sizes):
    """font-size: Npx → font-size: {_VAR}px 치환."""
    for px in sizes:
        vname = var_name_for_size(px)
        source = re.sub(
            rf'font-size:\s*{px}px',
            f'font-size: {{{vname}}}px',
            source
        )
    return source


def replace_line_heights(source, lh_dict):
    """line-height 값 치환."""
    for _, (kind, val) in lh_dict.items():
        vname = var_name_for_lh(kind, val)
        if kind == "px":
            source = re.sub(
                rf'line-height:\s*{val}px',
                f'line-height: {{{vname}}}px',
                source
            )
        else:
            source = re.sub(
                rf'line-height:\s*{re.escape(str(val))}(?![0-9])',
                f'line-height: {{{vname}}}',
                source
            )
    return source


def replace_font_path(source):
    """폰트 경로 치환."""
    return source.replace(FONT_PATH_HARD, f'file://{{FONT_DIR}}')


def replace_workspace_paths(source):
    """Path("/home/jay/workspace/...") → WORKSPACE_ROOT / "..." 치환."""
    return re.sub(
        r'Path\("' + re.escape(WORKSPACE_HARD) + r'([^"]+)"\)',
        r'WORKSPACE_ROOT / "\1"',
        source
    )


def remove_local_font_dir(source):
    """로컬 FONT_DIR 정의 제거."""
    source = re.sub(
        r'\nFONT_DIR\s*=\s*Path\.home\(\)\s*/\s*["\'].local/share/fonts["\'].*\n',
        '\n',
        source
    )
    source = re.sub(
        r'\nFONT_DIR\s*=\s*Path\.home\(\)\s*/\s*["\'].local/share/fonts/Pretendard["\'].*\n',
        '\n',
        source
    )
    return source


# ── Type F: f-string 파일 처리 ──
def process_type_f(filepath):
    """f-string 템플릿 파일: 값 치환 + import 추가."""
    source = filepath.read_text(encoding="utf-8")
    sizes, lh_dict = collect_values(source)
    has_fp = FONT_PATH_HARD in source
    has_wp = WORKSPACE_HARD in source and 'Path("' + WORKSPACE_HARD in source

    source = replace_font_sizes(source, sizes)
    source = replace_line_heights(source, lh_dict)
    source = replace_font_path(source)
    source = replace_workspace_paths(source)
    source = remove_local_font_dir(source)

    symbols, defs = build_imports_and_defs(sizes, lh_dict, has_fp, has_wp)
    source = insert_imports_at_top(source, symbols, defs)

    filepath.write_text(source, encoding="utf-8")
    return {"sizes": sorted(sizes), "lh": len(lh_dict)}


# ── Type A: .format() 호환 파일 처리 ──
def find_template_ranges(source):
    """HTML 템플릿 문자열의 (start, end) 범위 반환."""
    ranges = []
    for m in re.finditer(r'= (""")(\\\s*<!DOCTYPE|\\?\n<!DOCTYPE|<!DOCTYPE)', source):
        start = m.start(1)
        end = source.find('"""', start + 3)
        if end != -1:
            end += 3
            ranges.append((start, end))
    return ranges


def process_type_a(filepath):
    """Group A: {{}} CSS + {bg_url} �� f-string 변환."""
    source = filepath.read_text(encoding="utf-8")
    ranges = find_template_ranges(source)
    sizes, lh_dict = collect_values(source)
    has_fp = FONT_PATH_HARD in source
    has_wp = 'Path("' + WORKSPACE_HARD in source

    for start, end in reversed(ranges):
        template = source[start:end]
        # Escape format placeholders
        template = re.sub(r'\{(bg_url|bg_path|font_dir)\}', r'{{\1}}', template)
        # Replace values
        for px in sizes:
            vname = var_name_for_size(px)
            template = re.sub(rf'font-size:\s*{px}px', f'font-size: {{{vname}}}px', template)
        for _, (kind, val) in lh_dict.items():
            vname = var_name_for_lh(kind, val)
            if kind == "px":
                template = re.sub(rf'line-height:\s*{val}px', f'line-height: {{{vname}}}px', template)
            else:
                template = re.sub(rf'line-height:\s*{re.escape(str(val))}(?![0-9])', f'line-height: {{{vname}}}', template)
        # Font path
        template = template.replace(FONT_PATH_HARD, f'file://{{FONT_DIR}}')
        # Add f prefix
        template = "f" + template
        source = source[:start] + template + source[end:]

    source = replace_workspace_paths(source)
    source = remove_local_font_dir(source)
    symbols, defs = build_imports_and_defs(sizes, lh_dict, has_fp, has_wp)
    source = insert_imports_at_top(source, symbols, defs)

    filepath.write_text(source, encoding="utf-8")
    return {"sizes": sorted(sizes), "lh": len(lh_dict)}


# ── Type B: raw CSS 파일 처리 ──
def process_type_b(filepath):
    """Group B: {} CSS (no .format()) → 중괄호 이중화 + f-string."""
    source = filepath.read_text(encoding="utf-8")
    # Find template ranges - may use """\ pattern
    ranges = []
    for m in re.finditer(r'= (""")(\\?\s*<!DOCTYPE|\\?\n<!DOCTYPE|<!DOCTYPE|\\\n)', source):
        start = m.start(1)
        end = source.find('"""', start + 3)
        if end != -1:
            end += 3
            ranges.append((start, end))

    sizes, lh_dict = collect_values(source)
    has_fp = FONT_PATH_HARD in source
    has_wp = 'Path("' + WORKSPACE_HARD in source

    for start, end in reversed(ranges):
        template = source[start:end]
        prefix = template[:3]
        suffix = template[-3:]
        inner = template[3:-3]

        # Double all braces
        inner = inner.replace("{", "{{").replace("}", "}}")

        # Replace values
        for px in sizes:
            vname = var_name_for_size(px)
            inner = re.sub(rf'font-size:\s*{px}px', f'font-size: {{{vname}}}px', inner)
        for _, (kind, val) in lh_dict.items():
            vname = var_name_for_lh(kind, val)
            if kind == "px":
                inner = re.sub(rf'line-height:\s*{val}px', f'line-height: {{{vname}}}px', inner)
            else:
                inner = re.sub(rf'line-height:\s*{re.escape(str(val))}(?![0-9])', f'line-height: {{{vname}}}', inner)

        # Font path (was doubled, now replace)
        doubled_fp = FONT_PATH_HARD.replace("{", "{{").replace("}", "}}")
        inner = inner.replace(doubled_fp, f'file://{{FONT_DIR}}')

        source = source[:start] + f'f{prefix}{inner}{suffix}' + source[end:]

    source = replace_workspace_paths(source)
    source = remove_local_font_dir(source)
    symbols, defs = build_imports_and_defs(sizes, lh_dict, has_fp, has_wp)
    source = insert_imports_at_top(source, symbols, defs)

    filepath.write_text(source, encoding="utf-8")
    return {"sizes": sorted(sizes), "lh": len(lh_dict)}


# ── 파일 분류 ──
TYPE_A_FILES = [
    "gen_cell1_incar_fair_banners.py",
    "gen_cell2_incar_leader_banners.py",
    "gen_m1_1_fair_banners.py",
    "gen_m1_2_leader_banners.py",
    "gen_m1_3_support_banners.py",
    "gen_07_impact_number_v2.py",
    "gen_14_svg_first_v2.py",
    "gen_concept30_hermes.py",
    "gen_incar_leader_banners.py",
]

TYPE_B_FILES = [
    "gen_cell7_snu_fair_banners.py",
    "gen_cell8_snu_leader_banners.py",
]

TYPE_F_FILES = [
    "gen_15_cjk_typography_v2.py",
    "gen_c26_production_banners.py",
    "gen_c35_production_banners.py",
    "gen_c38_cannes_grid_banners.py",
    "gen_concept31_patagonia.py",
    "gen_concepts_21_22_23.py",
    "gen_concepts_24_26.py",
    "gen_m3_1_banners.py",
    "gen_m3_2_banners.py",
    "gen_m3_3_banners.py",
    "gen_snu_fair_banners.py",
]


def main():
    all_files = TYPE_A_FILES + TYPE_B_FILES + TYPE_F_FILES
    print(f"마이그레이션 대상: {len(all_files)}개 파일")
    print("=" * 60)

    for f in TYPE_F_FILES:
        r = process_type_f(DIR / f)
        print(f"  [F] {f} — sizes={r['sizes']}, lh={r['lh']}")

    for f in TYPE_A_FILES:
        r = process_type_a(DIR / f)
        print(f"  [A] {f} — sizes={r['sizes']}, lh={r['lh']}")

    for f in TYPE_B_FILES:
        r = process_type_b(DIR / f)
        print(f"  [B] {f} — sizes={r['sizes']}, lh={r['lh']}")

    # 검증
    print("\n" + "=" * 60)
    print("검증")
    errors = 0
    for f in all_files:
        content = (DIR / f).read_text()
        issues = []
        if re.search(r'font-size:\s*\d+px', content):
            issues.append("font-size")
        if re.search(r'line-height:\s*\d+px', content) and '{_' not in content:
            cnt = len(re.findall(r'line-height:\s*\d+px', content))
            issues.append(f"lh-px:{cnt}")
        if FONT_PATH_HARD in content:
            issues.append("font-path")
        if f'Path("{WORKSPACE_HARD}' in content:
            issues.append("ws-path")

        try:
            ast.parse(content)
        except SyntaxError as e:
            issues.append(f"syntax:{e.lineno}")

        if issues:
            print(f"  [FAIL] {f}: {', '.join(issues)}")
            errors += 1
        else:
            print(f"  [OK] {f}")

    if errors:
        print(f"\n{errors}건 에러")
        sys.exit(1)
    else:
        print("\n모든 검증 통과!")


if __name__ == "__main__":
    main()
