"""Seed the League & Williams project — run once inside the container:

    docker exec easel-app python -m app.seed_league

Idempotent: each piece checks before creating, so a re-run repairs gaps and
changes nothing that exists. Content sources:
  * bundles copied to /data/seed/league/ (from leaguelaw's prototyping library)
  * walkthrough copy adapted from Adi's designer notes
    (leaguelaw notes/designer-notes-pins-homepage.md, 2026-08-31) — his words,
    condensed to the 5-beat seed walkthrough; the full 39-pin plan is his to
    finish in the app.

Left deliberately UNSENT (state stays in_progress): presenting to the client is
rian's call, made in the UI when he has told darren himself.
"""

import logging
import re

from sqlalchemy import select

from app import accounts
from app import bw_accounts as bwa
from app.config import get_settings
from app.db import get_session_factory
from app.models import Option, Screen, WalkthroughStep
from app.services import mockups
from app.services import projects as svc

log = logging.getLogger("seed_league")

PROJECT_ID = "league"
PROJECT_LABEL = "League & Williams website concepts"
# THE CLIENT READS THIS, under the project title. Written to darren, not to us
# — the seeding provenance, the curation state and the option-ordering plan are
# ours and belong in the handoff, not on the page he opens.
DESCRIPTION = (
    "Homepage concepts for review. Open one, leave a note anywhere on it, and "
    "choose the direction that feels right."
)

SEED_DIR = "seed/league"

# Relative image references in the seed pages: <img src="img/NAME">.
IMG_REF = re.compile(r'src="img/([^"]+)"')

# (screen, [(title, badge, file)]) — names for the client, not for us (Adi).
#
# TWO options, per rian's M2 ask 3: a concept is a couple of options with
# toggles inside them, not one option per combination. The third opening (The
# Welcome Desk, form-only hero) is retired from the seed rather than deleted —
# its file is still in the bundle if it is ever wanted back.
#
# Option 2's hero is REDUCED to the live site's own height (655px, measured from
# the replica) rather than the full-viewport treatment — rian's ask 4.
CONTENT = [
    ("Homepage", [
        ("The Direct Answer", "No hero", "home-direct-answer.html"),
        ("The Welcome Desk", "Short hero", "home-welcome-desk-short-hero.html"),
    ]),
    ("Your Team", [
        ("The Bench", "Matches The Direct Answer", "team-bench.html"),
    ]),
]

# The 5-beat walkthrough on the entry option, in Adi's voice (notes Set A + Z,
# condensed). Targets are CSS SELECTORS resolved against the live mockup by the
# viewer bridge — the spotlight then hugs the real element at whatever size it
# renders. (Hand-guessed percentage rects were the first attempt and highlighted
# the wrong thing: a percentage of a 4,600px page is an enormous band.)
# Selectors verified present in home_v1: .nheader .phone .triage .cband .ctaband
# (.phone is the header number; .rcall looks right but matches six hidden copies
# inside the hover mega-menus — always target what is actually on screen.)
WALKTHROUGH = [
    ("Start here", (
        "Welcome! Use Next to walk through what each part of the design is "
        "doing for you. The photos are blurred on purpose. The real "
        "photography comes from the November shoot, so today we are looking "
        "at layout rather than pictures."), ".nheader", False),
    ("Your number, in your face", (
        "Front and centre on every page, at full size and tappable to call, "
        "exactly as you asked. Never buried in a footer."),
     ".phone", False),
    ("Your issue, one click", (
        "No hero image, on purpose. We took your direction literally, so "
        "the practice areas are the first thing on the screen. Five teams, "
        "readable in two seconds. A visitor thinks \"yes, that is my "
        "issue\" and clicks."),
     ".triage", False),
    ("A league, not a lawyer", (
        "Your core idea as the loudest statement on the page, next to a "
        "call-back form that takes ten seconds."),
     ".cband", False),
    ("Two decisions, that's all", (
        "Pick an opening with the Choose button in the option list: The "
        "Direct Answer, The Welcome Desk, or The Bold Welcome. Everything "
        "below it is already built and identical in each. Approving this "
        "step tells us you have seen the walkthrough."),
     ".ctaband", True),
]

CLIENTS = [("darren", "member")]


def run() -> None:
    settings = get_settings()
    accounts.init_accounts_kit()

    # 1. The instance.
    if not any(i["id"] == PROJECT_ID for i in bwa.instances()):
        bwa.create_instance("rian", PROJECT_ID, PROJECT_LABEL)
        log.info("created instance %s", PROJECT_ID)

    # 2. Client memberships + per-instance grants (never app-wide).
    for username, level in CLIENTS:
        if not bwa.member(username):
            bwa.add_member("rian", username, level, all_instances=False)
            log.info("added member %s (%s)", username, level)
        member = bwa.member(username)
        if PROJECT_ID not in (member.get("grants") or {}):
            bwa.grant_instance("rian", username, PROJECT_ID, level)
            log.info("granted %s on %s", username, PROJECT_ID)

    sf = get_session_factory()
    with sf() as db:
        details = svc.ensure_details(db, PROJECT_ID)
        if not details.description:
            details.description = DESCRIPTION

        # 3. Screens, options, bundles.
        seed_root = settings.data_dir / SEED_DIR
        entry_option_id: int | None = None
        for screen_title, options in CONTENT:
            screen = db.scalar(select(Screen).where(
                Screen.instance_id == PROJECT_ID,
                Screen.title == screen_title))
            if screen is None:
                screen = svc.add_screen(db, PROJECT_ID, screen_title)
                log.info("created screen %s", screen_title)
            for title, badge, filename in options:
                option = db.scalar(select(Option).where(
                    Option.screen_id == screen.id, Option.title == title))
                if option is None:
                    option = svc.add_option(db, screen, title, badge)
                    log.info("created option %s", title)
                if screen_title == "Homepage" and entry_option_id is None:
                    entry_option_id = option.id
                if not option.files:
                    source = seed_root / filename
                    if not source.exists():
                        log.warning("seed file missing: %s — skipped", source)
                        continue
                    html = source.read_bytes()
                    mockups.store_file(db, option, "index.html", html)
                    option.entry_path = "index.html"
                    # The bundle's images: these pages reference img/<name>
                    # relatively, so the whole bundle must live in easel's own
                    # storage — a mockup that pulls assets from anywhere else
                    # is not self-contained and renders broken.
                    stored_imgs = 0
                    for name in sorted(set(IMG_REF.findall(html.decode(
                            "utf-8", "replace")))):
                        img = seed_root / "img" / name
                        if not img.exists():
                            log.warning("missing image %s for %s", name, title)
                            continue
                        mockups.store_file(db, option, f"img/{name}",
                                           img.read_bytes())
                        stored_imgs += 1
                    log.info("stored bundle for %s (+%d images)",
                             title, stored_imgs)

        # 4. The walkthrough, on the entry option only (Adi's rule: the
        # walkthrough lives once; every other option carries only differences).
        if entry_option_id is not None:
            existing = db.scalar(select(WalkthroughStep).where(
                WalkthroughStep.option_id == entry_option_id))
            if existing is None:
                for order, (title, body, selector, needs) in enumerate(
                        WALKTHROUGH, 1):
                    db.add(WalkthroughStep(
                        option_id=entry_option_id, step_order=order,
                        title=title, body_md=body, target_selector=selector,
                        rect=None, requires_approval=needs, created_by="rian"))
                log.info("authored %d walkthrough steps", len(WALKTHROUGH))

        svc.record(db, PROJECT_ID, "rian", "seeded",
                   {"source": "leaguelaw/prototyping", "by": "claude"})
        db.commit()

    print("seed complete: project 'league' with", len(CONTENT), "screens")


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
    run()
