#!/usr/bin/env python
"""
Extract per-course detail content from orthoglobe-courses.html:
  - Course Overview (p under <h2>Course Overview)
  - Who Should Attend (ul list)
  - Learning Outcomes (p.outcome-text inside div.outcome-card)
  - Course Highlights (h4 + p inside div.highlight-card)
  - Why This Course Is Different (p list)
  - Programme (div.programme-item → time + title + li list)
  - What Participants Say (h3 + p pairs)
  - Course Convenor (name + role + bio)

Writes src/data/academy/courses-detail.json.

Uses regex-based slicing on the three course page sections identified by
id="page-frcs" / id="page-shoulder" / id="page-msk" — the markup is generated
from a template and very consistent so regex is reliable here.
"""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
SITE = Path(__file__).resolve().parents[1]
SRC = ROOT / "orthoglobe-courses.html"
OUT = SITE / "src" / "data" / "academy" / "courses-detail.json"

COURSE_SLUGS = {
    "page-frcs": "chertsey-frcs-course",
    "page-shoulder": "london-shoulder-masterclass",
    "page-msk": "advanced-msk-primary-care",
}


def strip_tags(s: str) -> str:
    return re.sub(r"\s+", " ", re.sub(r"<[^>]+>", "", s)).strip()


def slice_courses(html: str) -> dict[str, str]:
    out: dict[str, str] = {}
    for page_id, slug in COURSE_SLUGS.items():
        m = re.search(
            r'id="' + page_id + r'"[^>]*>(.*?)(?=id="page-|</body>)',
            html,
            flags=re.DOTALL,
        )
        if m:
            out[slug] = m.group(1)
    return out


def _section_between(block: str, h2_label: str) -> str | None:
    m = re.search(
        r"<h2[^>]*>\s*" + re.escape(h2_label) + r"\s*</h2>(.*?)(?:<h2|<section|</section)",
        block,
        flags=re.DOTALL,
    )
    return m.group(1) if m else None


def extract_overview(block: str) -> str:
    section = _section_between(block, "Course Overview")
    if not section:
        return ""
    paras = re.findall(r"<p[^>]*>(.*?)</p>", section, flags=re.DOTALL)
    return " ".join(strip_tags(p) for p in paras).strip()


def extract_who(block: str) -> list[str]:
    section = _section_between(block, "Who Should Attend")
    if not section:
        return []
    items = re.findall(r"<li[^>]*>(.*?)</li>", section, flags=re.DOTALL)
    return [strip_tags(i) for i in items if strip_tags(i)]


def extract_outcomes(block: str) -> list[str]:
    section = _section_between(block, "Learning Outcomes")
    if not section:
        return []
    cards = re.findall(
        r'<p class="outcome-text"[^>]*>(.*?)</p>', section, flags=re.DOTALL,
    )
    return [strip_tags(c) for c in cards if strip_tags(c)]


def extract_highlights(block: str) -> list[dict]:
    section = _section_between(block, "Course Highlights")
    if not section:
        return []
    cards = re.findall(
        r'<div class="highlight-card"[^>]*>\s*<h4[^>]*>(.*?)</h4>\s*<p[^>]*>(.*?)</p>',
        section,
        flags=re.DOTALL,
    )
    return [{"title": strip_tags(t), "body": strip_tags(b)} for t, b in cards]


def extract_why_different(block: str) -> list[str]:
    section = _section_between(block, "Why This Course Is Different")
    if not section:
        return []
    items = re.findall(r"<li[^>]*>(.*?)</li>", section, flags=re.DOTALL)
    if items:
        return [strip_tags(i) for i in items if strip_tags(i)]
    paras = re.findall(r"<p[^>]*>(.*?)</p>", section, flags=re.DOTALL)
    return [strip_tags(p) for p in paras if strip_tags(p)]


def extract_programme(block: str) -> list[dict]:
    section = _section_between(block, "Programme")
    if not section:
        return []
    # Split the section at every `programme-item` boundary — each slice then
    # contains one card's full content. We can't use balanced-paren matching
    # with re, but splitting on the open tag works for this template.
    chunks = re.split(r'<div class="programme-item"[^>]*>', section)[1:]
    out: list[dict] = []
    for raw in chunks:
        # Take everything up to the next programme-item (already split) but cap
        # at the next `</section>` or `<h2>` to avoid bleeding past the section.
        raw = re.split(r"</section|<h2[^>]*>", raw)[0]
        time_match = re.search(
            r'<div class="programme-time[^"]*"[^>]*>(.*?)</div>',
            raw,
            flags=re.DOTALL,
        )
        title_match = re.search(
            r'<div class="programme-title[^"]*"[^>]*>(.*?)</div>',
            raw,
            flags=re.DOTALL,
        )
        lis = re.findall(r"<li[^>]*>(.*?)</li>", raw, flags=re.DOTALL)
        out.append(
            {
                "time": strip_tags(time_match.group(1)) if time_match else "",
                "title": strip_tags(title_match.group(1)) if title_match else "",
                "items": [strip_tags(i) for i in lis if strip_tags(i)],
            },
        )
    return out


def extract_testimonials(block: str) -> list[dict]:
    section = _section_between(block, "What Participants Say")
    if not section:
        return []
    # The template uses either <blockquote> with attribution or h3 + p pairs.
    quotes = re.findall(
        r'<blockquote[^>]*>(.*?)</blockquote>\s*(?:<cite[^>]*>(.*?)</cite>)?',
        section,
        flags=re.DOTALL,
    )
    if quotes:
        return [
            {"quote": strip_tags(q), "author": strip_tags(a) if a else ""}
            for q, a in quotes
        ]
    # Fallback: match <p class="testimonial-quote">...</p><p class="testimonial-author">...</p>
    cards = re.findall(
        r'testimonial-quote[^>]*>(.*?)</p>.*?testimonial-author[^>]*>(.*?)</p>',
        section,
        flags=re.DOTALL,
    )
    if cards:
        return [{"quote": strip_tags(q), "author": strip_tags(a)} for q, a in cards]
    # Last fallback: alternating h3 (author) + p (quote)
    out: list[dict] = []
    pattern = re.findall(
        r"<h3[^>]*>(.*?)</h3>\s*<p[^>]*>(.*?)</p>",
        section,
        flags=re.DOTALL,
    )
    for author, quote in pattern:
        out.append({"quote": strip_tags(quote), "author": strip_tags(author)})
    return out


def extract_convenor(block: str) -> dict | None:
    # Course Convenor is under h3, but the block has a consistent convenor-mini structure.
    m = re.search(
        r'<h3[^>]*>Course Convenor</h3>(.*?)(?=<h3|<h2|</section)',
        block,
        flags=re.DOTALL,
    )
    if not m:
        return None
    inner = m.group(1)
    name_m = re.search(r"<h4[^>]*>(.*?)</h4>", inner, flags=re.DOTALL)
    role_m = re.search(
        r"<h4[^>]*>.*?</h4>\s*<p[^>]*>(.*?)</p>", inner, flags=re.DOTALL,
    )
    bio_m = re.search(
        r'<p class="convenor-mini-bio"[^>]*>(.*?)</p>',
        inner,
        flags=re.DOTALL,
    )
    badges = re.findall(
        r'<span class="convenor-mini-badge"[^>]*>(.*?)</span>',
        inner,
        flags=re.DOTALL,
    )
    return {
        "name": strip_tags(name_m.group(1)) if name_m else "",
        "role": strip_tags(role_m.group(1)) if role_m else "",
        "bio": strip_tags(bio_m.group(1)) if bio_m else "",
        "badges": [strip_tags(b) for b in badges if strip_tags(b)],
    }


def main() -> int:
    if not SRC.exists():
        print(f"missing: {SRC}", file=sys.stderr)
        return 1

    html = SRC.read_text(encoding="utf-8")
    courses_html = slice_courses(html)

    result: dict[str, dict] = {}
    for slug, block in courses_html.items():
        result[slug] = {
            "slug": slug,
            "overview": extract_overview(block),
            "whoShouldAttend": extract_who(block),
            "outcomes": extract_outcomes(block),
            "highlights": extract_highlights(block),
            "whyDifferent": extract_why_different(block),
            "programme": extract_programme(block),
            "testimonials": extract_testimonials(block),
            "convenor": extract_convenor(block),
        }

    OUT.parent.mkdir(parents=True, exist_ok=True)
    OUT.write_text(
        json.dumps({"courses": result}, indent=2, ensure_ascii=False),
        encoding="utf-8",
    )

    for slug, c in result.items():
        counts = {
            k: (len(v) if isinstance(v, list) else ("set" if v else "empty"))
            for k, v in c.items()
            if k != "slug"
        }
        print(f"{slug} -> {counts}")

    print(f"\nwrote {OUT.relative_to(SITE)}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
