"""Generate recording scripts, filenames, pronunciation sheets and actor directions."""

from __future__ import annotations

import csv
import json
import re
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"))

ACTOR_GUIDANCE = {
"en":"Use the approved regional English variety. Keep child-directed speech natural; do not over-enunciate articles or final consonants unless the pronunciation sheet explicitly requests a teaching take.",
"hi":"Record natural Hindi in the approved regional variety. Preserve schwa deletion, aspiration, vowel length, gender agreement and respectful register; do not read Devanagari as if every written vowel is fully pronounced.",
"ta":"Record the approved spoken Tamil variety, not an artificially literary reading unless marked. Preserve vowel length, retroflex contrasts and natural child-directed rhythm.",
"te":"Record natural Telugu with approved regional pronunciation. Preserve vowel length, retroflex contrasts, gemination and natural person/honorific agreement.",
"kn":"Record natural Kannada in the approved variety. Preserve vowel length, retroflex contrasts and gemination; avoid replacing familiar child-directed forms with overly formal reading forms.",
"ml":"Record natural Malayalam in the approved variety. Preserve vowel length, retroflex contrasts, gemination and chillu-related pronunciation; use spoken forms where the approved script specifies them.",
"mr":"Record natural Marathi, not Hindi-influenced substitutions. Preserve vowel quality, retroflex contrasts, gender/number agreement and the approved familiar or respectful register.",
"bn":"Record natural Bengali in the approved regional variety. Preserve vowel quality, aspiration, consonant contrasts and honorific level; do not infer pronunciation mechanically from spelling where common spoken forms differ.",
}


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


def safe_key(value: str) -> str:
    value = re.sub(r"[^a-z0-9]+", "_", value.lower()).strip("_")
    return value[:96]


def filename(concept: str, language: str, semantic_key: str) -> str:
    return f"{concept}__{language}__{safe_key(semantic_key)}__take01.wav"


queue_header = ["recording_key","concept_key","language","semantic_key","audience","filename","script_status","voice_actor","pronunciation_review","native_review","slp_review","release_reference","recording_status","checksum","notes"]
queue = [queue_header]
updated = 0
utterance_total = 0

for concept in PLAN["concepts"]:
    base = concept_path(concept)
    for lang in PLAN["languages"]:
        code = lang["code"]
        locale = base / "locales" / code
        audio = locale / "audio"
        package = json.loads((locale / "translation-package.json").read_text(encoding="utf-8"))
        target = package["target_content"]
        utterances = []

        def add(key: str, audience: str, source: str | None, target_text: str | None, purpose: str, difficulty: int | None = None) -> None:
            if not target_text:
                status = "blocked_translation_required"
            elif code == "en":
                status = "script_ready_review_required"
            else:
                status = "blocked_native_translation_review_required"
            utterances.append({
                "recording_key": f"{concept['key']}.{code}.{key}",
                "semantic_key": key,
                "audience": audience,
                "purpose": purpose,
                "difficulty": difficulty,
                "source_meaning_en": source,
                "approved_target_text": target_text,
                "filename_take_01": filename(concept["key"], code, key),
                "alternate_take_pattern": filename(concept["key"], code, key).replace("take01", "take{take_number:02d}"),
                "performance": "natural child-directed neutral",
                "pace": "comfortable; preserve natural connected speech",
                "record_as_single_utterance": True,
                "status": status,
            })

        add("label", "learner", package["english_reference"]["preferred_label"], target["preferred_term"], "isolated_label", 1)
        if target["aac_short_label"] and target["aac_short_label"].casefold() != (target["preferred_term"] or "").casefold():
            add("aac_short_label", "learner", package["english_reference"]["preferred_label"], target["aac_short_label"], "aac_label", 1)
        for expression in target["expressions"]:
            add(expression["semantic_key"], "learner", expression["source_meaning_en"], expression["target_text"], "learning_expression", expression.get("difficulty"))
        for direction in target["caregiver_directions"]:
            add(f"caregiver.direction.{direction['source_step']:02d}", "caregiver_or_clinician", direction["source_meaning_en"], direction["target_text"], "caregiver_direction")

        script = {
            "schema_version": 1,
            "recording_pack_key": f"{concept['key']}.{code}",
            "concept_key": concept["key"],
            "language": package["target_language"],
            "source_package": "../translation-package.json",
            "recording_order": "label, learner-facing expressions, optional caregiver directions",
            "utterance_count": len(utterances),
            "utterances": utterances,
            "status": "ready_for_script_review" if code == "en" else "awaiting_approved_translation",
        }
        script_path = audio / "recording-script.json"
        text = json.dumps(script, ensure_ascii=False, indent=2) + "\n"
        if not script_path.exists() or script_path.read_text(encoding="utf-8") != text:
            script_path.write_text(text, encoding="utf-8"); updated += 1

        sheet = {
            "schema_version": 1,
            "concept_key": concept["key"],
            "language_code": code,
            "language_name": lang["name"],
            "script": lang["script"],
            "variety_to_record": None,
            "speaker_profile": {"adult_or_age_appropriate_voice": None,"regional_background": None,"register": "warm neutral child-directed","release_reference": None},
            "entries": [{
                "semantic_key": u["semantic_key"],
                "approved_text": u["approved_target_text"],
                "phonemic_or_ipa_optional": None,
                "syllable_breakdown_optional": None,
                "lexical_stress_or_prominence": None,
                "tone_or_intonation": "natural statement or question matching communicative intent",
                "acceptable_variants": [],
                "unacceptable_or_confusable_variants": [],
                "clinician_notes": None,
                "native_reviewer": None,
                "status": "pronunciation_review_required" if u["approved_target_text"] else "blocked_translation_required",
            } for u in utterances],
            "approval":{"native_pronunciation_reviewer":None,"speech_language_professional":None,"approved":False},
        }
        (audio / "pronunciation-sheet.json").write_text(json.dumps(sheet, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")

        directions = f"""# Voice-actor directions: {concept['name']} — {lang['name']}

Record only text marked approved in `recording-script.json`. Do not translate, paraphrase or correct wording during the session. Stop and flag unnatural or ambiguous text for the native reviewer.

## Performance

- Speak warmly, calmly and respectfully to one learner; avoid baby voice, exaggerated cheerfulness or theatrical emotion.
- Keep normal connected-speech rhythm. Do not over-enunciate unless a separate teaching take is explicitly requested.
- Preserve the communicative function: requests should sound genuinely useful, questions should have natural intonation, and feedback should remain neutral and non-judgmental.
- Record every line as an independent utterance. Do not add the concept label, explanations, counting, clicks or slate speech.
- For `stop`, `no`, refusal and help messages, sound clear and immediately understandable without sounding angry or coercive.
- For caregiver directions, use a collaborative professional tone, not a command directed at the learner.

## Language-specific direction

{ACTOR_GUIDANCE[code]}

## Technical capture

- Quiet treated room; one consistent microphone position 15–20 cm from the mouth with pop protection.
- Mono WAV, linear PCM, 48 kHz, 24-bit; never record directly to MP3.
- Capture 250–500 ms clean room tone before and after each utterance.
- Aim for approximately -20 LUFS integrated per short utterance after non-destructive normalization; true peak must remain at or below -3 dBTP.
- No music, reverb, noise gate pumping, pitch correction, voice cloning or aggressive denoising.
- Keep raw takes immutable outside the delivery folder; export selected masters using the exact filenames in the script.
- Record at least two clean takes. Add further takes only for a documented pronunciation, pacing or noise issue.

## Session and safeguarding

- Confirm the actor release and approved language variety before recording; store releases outside this content repository and reference only their identifier.
- Do not record identifiable learners or confidential clinical material.
- Permit breaks and stop immediately on discomfort. Do not imitate a disability, accent or child voice stereotypically.
- The actor may flag culturally inappropriate or unnatural wording without being asked to improvise a replacement on mic.

## Acceptance checks

- Filename matches the manifest exactly.
- Spoken words match approved text exactly while remaining natural.
- No clipping, mouth clicks, background speech, electrical hum or abrupt cutoffs.
- Native reviewer approves pronunciation and variety.
- SLP approves clarity, pacing and communicative function.
- Editor records duration, loudness, checksum, selected take, actor release reference and review status in `assets.csv`.
"""
        (audio / "voice-actor-directions.txt").write_text(directions.rstrip() + "\n", encoding="utf-8")

        assets_header = ["asset_key","filename","expression_key","speaker_variety","speaker_release","sample_rate","loudness_lufs","duration_ms","checksum","status","review_notes"]
        with (audio / "assets.csv").open("w", encoding="utf-8", newline="") as stream:
            writer = csv.writer(stream); writer.writerow(assets_header)
            for u in utterances:
                writer.writerow([u["recording_key"],u["filename_take_01"],u["semantic_key"],"","",48000,-20,"","",u["status"],"Native pronunciation SLP technical and rights review required"])
                queue.append([u["recording_key"],concept["key"],code,u["semantic_key"],u["audience"],u["filename_take_01"],u["status"],"","pending","pending","pending","","not_recorded",u["source_meaning_en"] or ""])
        utterance_total += len(utterances)

tracking = ROOT / "tracking" / "recording-queue.csv"
with tracking.open("w", encoding="utf-8", newline="") as stream:
    csv.writer(stream).writerows(queue)
print(f"Recording packs ready: {len(PLAN['concepts']) * len(PLAN['languages'])}; utterances: {utterance_total}; scripts updated: {updated}")
