"""Populate production-ready draft briefs throughout the speech content scaffold.

The script is idempotent: it creates missing derived content and never overwrites
human-edited files. Binary media remains a reviewed production task.
"""

from __future__ import annotations

import csv
import json
from collections import defaultdict
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1] / "content" / "speech"
PLAN = json.loads((ROOT / "plan" / "content-plan.json").read_text(encoding="utf-8"))


def once(path: Path, value: str) -> bool:
    path.parent.mkdir(parents=True, exist_ok=True)
    if path.exists():
        return False
    path.write_text(value.rstrip() + "\n", encoding="utf-8")
    return True


def json_once(path: Path, value: object) -> bool:
    return once(path, json.dumps(value, ensure_ascii=False, indent=2))


def concept_path(concept: dict) -> Path:
    return ROOT / "concepts" / Path(*concept["category"].split(".")) / concept["key"]


def node_path(node: dict) -> Path:
    return ROOT / "capabilities" / node["capability"] / "nodes" / f"l{node['level']:02d}_{node['key']}"


def article(name: str) -> str:
    return "an" if name[:1].lower() in "aeiou" else "a"


def definitions(concept: dict) -> tuple[str, list[str]]:
    name, kind, category = concept["name"], concept["type"], concept["category"]
    if kind == "action":
        return f"The observable action or communicative meaning of '{name.lower()}', shown across different people, objects and everyday contexts.", ["a still image where the action cannot be inferred", "an unrelated action", "text without a meaningful example"]
    if kind in {"attribute", "quantity", "preposition"}:
        return f"The relational meaning of '{name.lower()}', demonstrated through a controlled contrast rather than colour, position or quantity in isolation.", ["an example without a contrasting referent", "a scene where another cue reveals the answer", "a culturally or linguistically different meaning"]
    if kind in {"social_word", "emotion"}:
        return f"The functional communicative meaning of '{name.lower()}' in a natural interaction, including context and partner response.", ["a decontextualized facial pose or word alone", "a different communicative intent", "an unsafe or coercive interaction"]
    if kind == "routine":
        return f"The familiar routine '{name.lower()}', represented as a meaningful ordered sequence with a clear beginning, middle and end.", ["a single ambiguous step", "the same actions in an incorrect order", "an unrelated routine"]
    return f"The language-independent concept of {article(name)} {name.lower()}, recognizable across real examples, viewpoints and contexts.", [f"a picture that only resembles {name.lower()}", "a printed word or logo instead of the concept", "an ambiguous or partially hidden target"]


def image_briefs(concept: dict) -> list[dict]:
    name = concept["name"]
    return [
        {"asset_key": f"{concept['key']}_isolated_01", "purpose": "identification", "difficulty": 1, "brief": f"One clear, realistic {name.lower()} centred on a plain neutral background; whole target visible; no text or logo.", "status": "brief_ready"},
        {"asset_key": f"{concept['key']}_natural_context_01", "purpose": "meaning", "difficulty": 1, "brief": f"A realistic everyday scene where {name.lower()} is the unambiguous target; simple background and one relevant contextual cue.", "status": "brief_ready"},
        {"asset_key": f"{concept['key']}_variation_01", "purpose": "generalisation", "difficulty": 2, "brief": f"A meaningfully different valid example of {name.lower()}—different instance, actor, form, size or setting without changing the concept.", "status": "brief_ready"},
        {"asset_key": f"{concept['key']}_viewpoint_01", "purpose": "generalisation", "difficulty": 2, "brief": f"The same concept {name.lower()} from a different viewpoint or distance, still fully recognizable and naturally lit.", "status": "brief_ready"},
        {"asset_key": f"{concept['key']}_context_complex_01", "purpose": "discrimination", "difficulty": 3, "brief": f"{name} in a moderately busy but realistic setting; target remains visible without positional or colour cueing.", "status": "brief_ready"},
        {"asset_key": f"{concept['key']}_unfamiliar_01", "purpose": "generalisation_probe", "difficulty": 3, "brief": f"A novel valid exemplar of {name.lower()} unlike the teaching set, suitable for an unprompted generalisation probe.", "status": "brief_ready"},
    ]


def video_briefs(concept: dict) -> list[dict]:
    name, kind = concept["name"], concept["type"]
    if kind in {"action", "routine", "social_word", "emotion"}:
        briefs = [
            f"A 5-8 second close, uncluttered real-world demonstration of {name.lower()}, with a clear start and finish.",
            f"A 6-10 second natural interaction showing {name.lower()} with a different person and setting; no acting exaggeration.",
            f"A novel 6-10 second example of {name.lower()} for generalisation, with the target moment visible without narration.",
        ]
    else:
        briefs = [
            f"A 5-8 second slow reveal and natural interaction with {name.lower()}, keeping the target in frame.",
            f"A 6-10 second functional everyday use of {name.lower()} by a person, without unnecessary spoken language.",
            f"A 6-10 second novel setting or instance of {name.lower()} for generalisation.",
        ]
    return [{"video_key": f"{concept['key']}_context_{i:02d}", "purpose": purpose, "brief": brief, "duration_seconds": "5-10", "language_scope": "language_neutral_preferred", "captions": "required_if_speech", "audio_description": "review_required", "rights": "release_required", "status": "brief_ready"} for i, (purpose, brief) in enumerate(zip(["model", "functional_context", "generalisation"], briefs), 1)]


concepts_by_group: dict[str, list[str]] = defaultdict(list)
for concept in PLAN["concepts"]:
    for group in concept["groups"]:
        concepts_by_group[group].append(concept["key"])
concepts_by_group["all"] = [item["key"] for item in PLAN["concepts"]]

nodes_for_group: dict[str, list[str]] = defaultdict(list)
for node in PLAN["nodes"]:
    for group in node["concept_groups"]:
        nodes_for_group[group].append(node["key"])

created = 0
for capability in PLAN["capabilities"]:
    nodes = [node for node in PLAN["nodes"] if node["capability"] == capability["key"]]
    created += json_once(ROOT / "capabilities" / capability["key"] / "content-plan.json", {
        "schema_version": 1,
        "capability_key": capability["key"],
        "purpose": capability["description"],
        "node_keys": [node["key"] for node in nodes],
        "production_sequence": ["clinical_scope", "concept_selection", "semantic_text", "media_briefs", "playable_activities", "accessibility_qa", "language_review", "clinical_approval"],
        "status": "draft_generated",
    })

for node in PLAN["nodes"]:
    base = node_path(node)
    eligible: list[str] = []
    for group in node["concept_groups"]:
        eligible.extend(concepts_by_group.get(group, []))
    eligible = list(dict.fromkeys(eligible))
    activities = [
        {"activity_key": f"{node['key']}_exposure", "template": "exposure", "purpose": "new", "field_size": 1, "prompt_start": "full_model_or_visual", "advance_when": "engagement_and_access_confirmed"},
        {"activity_key": f"{node['key']}_recognition", "template": "single_choice", "purpose": "acquisition", "field_size": 2, "prompt_start": "least_supportive_safe_prompt", "advance_when": "3_independent_correct"},
        {"activity_key": f"{node['key']}_discrimination", "template": "discrimination", "purpose": "practice", "field_size": "2_to_4", "prompt_start": "independent", "advance_when": "accuracy_and_independence_threshold_met"},
        {"activity_key": f"{node['key']}_functional_use", "template": "natural_routine", "purpose": "generalisation", "field_size": "contextual", "prompt_start": "natural_cue", "advance_when": "demonstrated_with_2_people_and_2_contexts"},
        {"activity_key": f"{node['key']}_retention", "template": "probe", "purpose": "maintenance", "field_size": "matched_to_last_success", "prompt_start": "independent", "advance_when": "retained_after_configured_interval"},
    ]
    packet = {
        "schema_version": 1,
        "node_key": node["key"],
        "goal": node["goal"],
        "eligible_concept_keys": eligible,
        "response_modes": ["touch", "pointing", "gesture", "eye_gaze", "aac", "sign", "vocalisation", "speech", "observed"],
        "prompt_hierarchy": ["independent", "natural_cue", "visual_cue", "gesture", "verbal_cue", "partial_model", "full_model", "physical_assistance"],
        "activities": activities,
        "difficulty_rules": {"increase": "3 consecutive independent correct responses", "decrease": "2 consecutive incorrect responses or increased distress", "hold": "prompt dependency is increasing", "clinician_override": True},
        "trial_fields": ["node", "concept", "language", "activity", "stimulus", "target", "distractors", "response_mode", "response", "correct", "prompt", "attempt", "latency_ms", "context", "partner", "rating", "timestamp"],
        "review_status": "clinical_review_required",
    }
    created += json_once(base / "activities" / "activity-briefs.json", packet)
    created += once(base / "content-checklist.md", f"""# {node['name']} content checklist

- [ ] Goal and observable response approved by SLP
- [ ] Mandatory, recommended and alternative prerequisites recorded
- [ ] Concept selection reviewed for child relevance and safety
- [ ] At least six varied exemplars available per active concept
- [ ] Beginner and harder distractor sets validated
- [ ] Non-speech and AAC pathways tested
- [ ] Prompt hierarchy and independent scoring tested
- [ ] Text and audio approved for each active language
- [ ] Clinic, home and generalisation contexts represented
- [ ] Rights, accessibility, technical and clinical QA complete
""")

for concept in PLAN["concepts"]:
    base = concept_path(concept)
    meaning, exclusions = definitions(concept)
    created += json_once(base / "definition.draft.json", {
        "schema_version": 1, "concept_key": concept["key"], "preferred_english_label": concept["name"],
        "meaning": meaning, "exclusions": exclusions, "clinical_status": "draft_needs_slp_review",
    })
    created += json_once(base / "images" / "production-briefs.json", {"schema_version": 1, "concept_key": concept["key"], "minimum_approved": 6, "briefs": image_briefs(concept)})
    created += json_once(base / "videos" / "production-briefs.json", {"schema_version": 1, "concept_key": concept["key"], "recommended_approved": 3, "briefs": video_briefs(concept)})
    relevant_nodes: list[str] = []
    for group in concept["groups"]:
        relevant_nodes.extend(nodes_for_group.get(group, []))
    relevant_nodes = list(dict.fromkeys(relevant_nodes))
    game_ideas = [
        {"game_key": f"{concept['key']}_find", "template": "single_choice", "purpose": "identify", "difficulty": 1, "target": concept["key"], "distractor_policy": "unrelated clear contrast", "response_modes": ["touch", "pointing", "eye_gaze", "aac"]},
        {"game_key": f"{concept['key']}_match", "template": "image_match", "purpose": "match", "difficulty": 1, "target": concept["key"], "distractor_policy": "one valid match plus clear non-match", "response_modes": ["touch", "pointing", "eye_gaze"]},
        {"game_key": f"{concept['key']}_discriminate", "template": "discrimination", "purpose": "discriminate", "difficulty": 2, "target": concept["key"], "distractor_policy": "same category only after clear contrast succeeds", "response_modes": ["touch", "pointing", "eye_gaze", "aac"]},
        {"game_key": f"{concept['key']}_use", "template": "natural_routine", "purpose": "functional_use", "difficulty": 2, "target": concept["key"], "distractor_policy": "meaningful choices in a real routine", "response_modes": ["gesture", "aac", "sign", "vocalisation", "speech", "observed"]},
        {"game_key": f"{concept['key']}_novel", "template": "probe", "purpose": "generalisation", "difficulty": 3, "target": concept["key"], "distractor_policy": "novel exemplar and balanced position", "response_modes": ["touch", "pointing", "eye_gaze", "aac", "gesture", "speech"]},
    ]
    created += json_once(base / "games" / "game-briefs.json", {"schema_version": 1, "concept_key": concept["key"], "applicable_node_keys": relevant_nodes, "games": game_ideas, "status": "design_review_required"})
    intents = [
        {"key": "label", "meaning": f"Communicate the label for {concept['name']}", "difficulty": 1},
        {"key": "identify_instruction", "meaning": f"Ask the learner to identify {concept['name']} without revealing its position", "difficulty": 1},
        {"key": "choice", "meaning": f"Offer {concept['name']} as one meaningful option", "difficulty": 1},
        {"key": "request", "meaning": f"Request {concept['name']} in a natural context", "difficulty": 2},
        {"key": "describe", "meaning": f"Describe a relevant property or action involving {concept['name']}", "difficulty": 2},
        {"key": "question", "meaning": f"Ask or answer a meaningful question involving {concept['name']}", "difficulty": 3},
    ]
    created += json_once(base / "text" / "semantic-intents.draft.json", {"schema_version": 1, "concept_key": concept["key"], "intents": intents, "status": "clinical_review_required"})
    for lang in PLAN["languages"]:
        locale = base / "locales" / lang["code"]
        work = {
            "schema_version": 1, "concept_key": concept["key"], "language": lang["code"],
            "semantic_source": {"meaning": meaning, "intents": intents},
            "required_outputs": ["preferred_term", "natural_alternates", "aac_short_label", "identify_instruction", "choice_form", "request_forms_by_stage", "description_forms", "question_forms", "grammar_notes", "pronunciation_notes", "native_audio_per_approved_form"],
            "reviewers_required": ["native_language_reviewer", "speech_language_professional"],
            "status": "translation_required" if lang["code"] != "en" else "english_draft_ready",
        }
        created += json_once(locale / "translation-work.json", work)
        if lang["code"] == "en":
            name = concept["name"]
            created += json_once(locale / "text.draft.json", {
                "schema_version": 1, "concept_key": concept["key"], "language": "en", "preferred_term": name,
                "aac_short_label": name,
                "expressions": [
                    {"semantic_key": "label", "text": name, "difficulty": 1},
                    {"semantic_key": "identify_instruction", "text": f"Show me {name.lower()}.", "difficulty": 1},
                    {"semantic_key": "choice", "text": f"Do you want {name.lower()}?", "difficulty": 1},
                    {"semantic_key": "request", "text": name, "difficulty": 1, "note": "Accept as a functional one-word request."},
                    {"semantic_key": "request", "text": f"Want {name.lower()}.", "difficulty": 2},
                    {"semantic_key": "request", "text": f"I want {name.lower()}.", "difficulty": 3},
                ],
                "review": {"status": "draft_needs_clinical_and_language_review"},
            })

inventory = {
    "schema_version": 1,
    "counts": {"capabilities": len(PLAN["capabilities"]), "nodes": len(PLAN["nodes"]), "concepts": len(PLAN["concepts"]), "languages": len(PLAN["languages"]), "planned_images": len(PLAN["concepts"]) * 6, "planned_videos": len(PLAN["concepts"]) * 3, "planned_games": len(PLAN["concepts"]) * 5},
    "generated_files_created_this_run": created,
    "important": "Briefs are generated drafts. Binary media, native translations, recordings and clinical approvals are not complete.",
}
json_once(ROOT / "tracking" / "generated-content-inventory.json", inventory)
print(json.dumps(inventory, ensure_ascii=False))

