"""
IDS Phase 4 (task-2390) — design-md 라이브러리 60→130+ 확장 회귀 테스트
"""
from __future__ import annotations

import re
from difflib import SequenceMatcher
from pathlib import Path

import pytest

DESIGN_MD_DIR = Path("/home/jay/workspace/resources/design-md")
INDEX_PATH = DESIGN_MD_DIR / "INDEX.md"
CONTRIBUTING_PATH = DESIGN_MD_DIR / "CONTRIBUTING.md"

REQUIRED_SECTIONS = [
    "Visual Theme",
    "Color Palette",
    "Typography",
    "Component",
    "Layout",
    ("Depth", "Elevation", "Shadow"),
    ("Do's", "Don'ts", "Dos", "Don't"),
    ("Agent Prompt", "Prompt Guide", "Agent Guide"),
]

REQUIRED_CATEGORIES = [
    "insurance/finance",
    "b2b",
    "b2c",
    "luxury",
    "tech",
    "minimal",
    "korean",
]

HEX_RE = re.compile(r"#[0-9A-Fa-f]{6}")

EXISTING_60_BRANDS = {
    "airbnb", "airtable", "apple", "bmw", "cal", "claude", "clay", "clickhouse",
    "cohere", "coinbase", "composio", "cursor", "elevenlabs", "expo", "ferrari",
    "figma", "framer", "hashicorp", "ibm", "intercom", "kraken", "lamborghini",
    "linear.app", "lovable", "minimax", "mintlify", "miro", "mistral.ai",
    "mongodb", "notion", "nvidia", "ollama", "opencode.ai", "pinterest",
    "posthog", "raycast", "renault", "replicate", "resend", "revolut",
    "runwayml", "sanity", "sentry", "spacex", "spotify", "stripe", "supabase",
    "superhuman", "tesla", "together.ai", "uber", "vercel", "voltagent", "warp",
    "webflow", "wise", "x.ai", "zapier",
}


def _list_brand_dirs() -> list[Path]:
    return sorted(
        p for p in DESIGN_MD_DIR.iterdir()
        if p.is_dir() and (p / "DESIGN.md").exists()
    )


def _read_design_md(brand_dir: Path) -> str:
    return (brand_dir / "DESIGN.md").read_text(encoding="utf-8")


def _has_section(content: str, marker) -> bool:
    if isinstance(marker, str):
        return marker.lower() in content.lower()
    return any(m.lower() in content.lower() for m in marker)


# Scenario 1: 60 -> 130+ 도달
def test_scenario_1_brand_count_at_least_130():
    brand_dirs = _list_brand_dirs()
    assert len(brand_dirs) >= 130, (
        f"FAIL: brand count = {len(brand_dirs)}, expected >= 130"
    )


# Scenario 2: 모든 신규 design-md 표준 8 섹션 준수
# (task-2390 신규 브랜드만 검증. 기존 60 브랜드는 보존 의무이지 검증 대상 아님.)
def test_scenario_2_new_design_md_have_8_sections():
    brand_dirs = _list_brand_dirs()
    new_brands = [d for d in brand_dirs if d.name not in EXISTING_60_BRANDS]
    failures: list[str] = []
    for d in new_brands:
        content = _read_design_md(d)
        missing = [
            (str(m) if isinstance(m, str) else m[0])
            for m in REQUIRED_SECTIONS
            if not _has_section(content, m)
        ]
        if missing:
            failures.append(f"{d.name}: missing {missing}")
    assert not failures, (
        f"FAIL: {len(failures)} new brands missing sections.\n"
        + "\n".join(failures[:10])
    )


# Scenario 3: INDEX.md 7 카테고리 분류 정확
def test_scenario_3_index_md_has_7_categories():
    assert INDEX_PATH.exists(), "FAIL: INDEX.md missing"
    content = INDEX_PATH.read_text(encoding="utf-8")
    missing_cats = [c for c in REQUIRED_CATEGORIES if c not in content]
    assert not missing_cats, f"FAIL: INDEX.md missing categories = {missing_cats}"


def test_scenario_3b_index_md_brand_count():
    content = INDEX_PATH.read_text(encoding="utf-8")
    count_match = re.search(r"(\d{3})\s*개", content)
    assert count_match, "FAIL: INDEX.md missing brand count"
    count = int(count_match.group(1))
    assert count >= 130, f"FAIL: INDEX.md displays {count}, expected >= 130"


# Scenario 4: 라이센스 보존 (open-design 추출분만)
def test_scenario_4_license_preservation():
    brand_dirs = _list_brand_dirs()
    open_design_extracts = [
        d for d in brand_dirs
        if "Apache-2.0" in _read_design_md(d)
        and "open-design" in _read_design_md(d).lower()
    ]
    failures = [d.name for d in open_design_extracts if not (d / "LICENSE").exists()]
    assert not failures, f"FAIL: open-design extracts missing LICENSE: {failures}"


# Scenario 5: 저작권 70%+ 직접 복제 자동 차단 mock 검증
def test_scenario_5_copyright_block_mock():
    assert CONTRIBUTING_PATH.exists(), "FAIL: CONTRIBUTING.md missing"
    content = CONTRIBUTING_PATH.read_text(encoding="utf-8")
    assert any(t in content for t in ["70%", "0.70", "0.7"]), (
        "FAIL: 70% threshold policy missing"
    )

    original = "The quick brown fox jumps over the lazy dog with golden shadow"
    copied = "The quick brown fox jumps over the lazy dog with silver light"
    ratio = SequenceMatcher(None, original, copied).ratio()
    assert ratio >= 0.70, f"FAIL: mock 비정상 ratio={ratio:.2f}"
    assert ratio >= 0.70, "FAIL: 80% case not blocked"


# Scenario 6: 130+ 모두 satori 호환
def test_scenario_6_all_design_md_satori_compatible():
    brand_dirs = _list_brand_dirs()
    failures: list[str] = []
    for d in brand_dirs:
        content = _read_design_md(d)
        hex_colors = HEX_RE.findall(content)
        if len(hex_colors) < 3:
            failures.append(f"{d.name}: only {len(hex_colors)} HEX")
    assert not failures, (
        f"FAIL: {len(failures)} brands not satori-compatible.\n"
        + "\n".join(failures[:10])
    )


# 추가: 기존 58 브랜드 보존
def test_existing_brands_preserved():
    brand_dirs = {d.name for d in _list_brand_dirs()}
    missing = EXISTING_60_BRANDS - brand_dirs
    assert not missing, f"FAIL: 기존 브랜드 누락: {missing}"


def test_contributing_md_exists():
    assert CONTRIBUTING_PATH.exists(), "FAIL: CONTRIBUTING.md missing"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
