"""
seed_greenfield_timetable.py — Full timetable + class + student seed for Greenfield Academy.

Flow:
   1. POST /timetable/setup              — academic year, 3 terms, periods → Supabase
   2. POST /timetable/materialize-periods — academic_periods rows (days × template)
   3. Create classes                     — 17 classes with correct metadata
   4. Add teachers to classes            — primary teacher per class
   5. POST /timetable/init + slots       — TeacherTimetable + slot assignments
   6. Patch slot class_ids               — write class_id FK onto teacher_timetable_slots
   7. Enroll students in classes         — student1→Yr9, student2→Yr10, student3→Yr11
   8. POST /timetable/materialize        — taught_lessons with class_id populated
   9. POST /timetable/sync-lessons       — Neo4j TaughtLesson nodes (B.10)

Run inside ccapi container:
    python3 -c "from run.initialization.seed_greenfield_timetable import seed; seed()"
"""
import os
import time
import requests
from typing import Dict, Any, Optional, List

SUPA_URL   = os.environ["SUPABASE_URL"]
SERVICE_KEY = os.environ["SERVICE_ROLE_KEY"]
API_BASE   = os.environ.get("API_BASE_URL", "http://localhost:8000")

GREENFIELD_ADMIN_EMAIL = "admin@greenfieldacademy.test"
GREENFIELD_ADMIN_PWD   = "Admin@Cc2025!"
PWD_TEACHER = "Teacher@Cc2025!"
PWD_STUDENT = "Student@Cc2025!"

# ─── Period templates ──────────────────────────────────────────────────────────

PERIODS = [
    {"code": "REG", "name": "Registration", "start_time": "08:45", "end_time": "09:00", "period_type": "registration"},
    {"code": "P1",  "name": "Period 1",     "start_time": "09:00", "end_time": "10:00", "period_type": "lesson"},
    {"code": "P2",  "name": "Period 2",     "start_time": "10:00", "end_time": "11:00", "period_type": "lesson"},
    {"code": "BRK", "name": "Break",        "start_time": "11:00", "end_time": "11:20", "period_type": "break"},
    {"code": "P3",  "name": "Period 3",     "start_time": "11:20", "end_time": "12:20", "period_type": "lesson"},
    {"code": "P4",  "name": "Period 4",     "start_time": "12:20", "end_time": "13:20", "period_type": "lesson"},
    {"code": "LUN", "name": "Lunch",        "start_time": "13:20", "end_time": "14:00", "period_type": "break"},
    {"code": "P5",  "name": "Period 5",     "start_time": "14:00", "end_time": "15:00", "period_type": "lesson"},
]

PERIOD_TIMES = {p["code"]: (p["start_time"], p["end_time"]) for p in PERIODS}

# ─── Academic year ─────────────────────────────────────────────────────────────

TERMS = [
    {"name": "Autumn Term", "term_number": 1, "start_date": "2025-09-03", "end_date": "2025-12-19"},
    {"name": "Spring Term", "term_number": 2, "start_date": "2026-01-05", "end_date": "2026-04-01"},
    {"name": "Summer Term", "term_number": 3, "start_date": "2026-04-20", "end_date": "2026-07-17"},
]

# ─── Class definitions ─────────────────────────────────────────────────────────
# Covers every unique subject_class code in TEACHER_SLOTS.
# key_stage: KS3 = years 7-9, KS4 = years 10-11, KS5 = years 12-13

CLASSES = [
    # Physics
    {"class_code": "9P/Ph1",  "name": "Year 9 Physics Group 1",   "subject": "Physics",     "year_group": "9",  "key_stage": "3", "teacher": "physics@greenfieldacademy.test"},
    {"class_code": "10P/Ph2", "name": "Year 10 Physics Group 2",  "subject": "Physics",     "year_group": "10", "key_stage": "4", "teacher": "physics@greenfieldacademy.test"},
    {"class_code": "11P/Ph1", "name": "Year 11 Physics Group 1",  "subject": "Physics",     "year_group": "11", "key_stage": "4", "teacher": "physics@greenfieldacademy.test"},
    {"class_code": "12P/Ph1", "name": "Year 12 Physics Group 1",  "subject": "Physics",     "year_group": "12", "key_stage": "5", "teacher": "physics@greenfieldacademy.test"},
    # Maths
    {"class_code": "9M/Ma1",  "name": "Year 9 Maths Group 1",    "subject": "Mathematics", "year_group": "9",  "key_stage": "3", "teacher": "maths@greenfieldacademy.test"},
    {"class_code": "10M/Ma1", "name": "Year 10 Maths Group 1",   "subject": "Mathematics", "year_group": "10", "key_stage": "4", "teacher": "maths@greenfieldacademy.test"},
    {"class_code": "11M/Ma2", "name": "Year 11 Maths Group 2",   "subject": "Mathematics", "year_group": "11", "key_stage": "4", "teacher": "maths@greenfieldacademy.test"},
    # English
    {"class_code": "7En/1",   "name": "Year 7 English Group 1",  "subject": "English",     "year_group": "7",  "key_stage": "3", "teacher": "teacher1@greenfieldacademy.test"},
    {"class_code": "8En/1",   "name": "Year 8 English Group 1",  "subject": "English",     "year_group": "8",  "key_stage": "3", "teacher": "teacher1@greenfieldacademy.test"},
    {"class_code": "9En/1",   "name": "Year 9 English Group 1",  "subject": "English",     "year_group": "9",  "key_stage": "3", "teacher": "teacher1@greenfieldacademy.test"},
    # History
    {"class_code": "8Hs/1",   "name": "Year 8 History Group 1",  "subject": "History",     "year_group": "8",  "key_stage": "3", "teacher": "teacher2@greenfieldacademy.test"},
    {"class_code": "9Hs/1",   "name": "Year 9 History Group 1",  "subject": "History",     "year_group": "9",  "key_stage": "3", "teacher": "teacher2@greenfieldacademy.test"},
    {"class_code": "10Hs/1",  "name": "Year 10 History Group 1", "subject": "History",     "year_group": "10", "key_stage": "4", "teacher": "teacher2@greenfieldacademy.test"},
    # Science
    {"class_code": "7Sc/1",   "name": "Year 7 Science Group 1",  "subject": "Science",     "year_group": "7",  "key_stage": "3", "teacher": "teacher3@greenfieldacademy.test"},
    {"class_code": "8Sc/1",   "name": "Year 8 Science Group 1",  "subject": "Science",     "year_group": "8",  "key_stage": "3", "teacher": "teacher3@greenfieldacademy.test"},
    {"class_code": "9Sc/1",   "name": "Year 9 Science Group 1",  "subject": "Science",     "year_group": "9",  "key_stage": "3", "teacher": "teacher3@greenfieldacademy.test"},
    {"class_code": "10Sc/1",  "name": "Year 10 Science Group 1", "subject": "Science",     "year_group": "10", "key_stage": "4", "teacher": "teacher3@greenfieldacademy.test"},
]

# ─── Teacher slot assignments ──────────────────────────────────────────────────

TEACHER_SLOTS = {
    "physics@greenfieldacademy.test": [
        ("Monday",    "P1", "11P/Ph1"),
        ("Monday",    "P3", "12P/Ph1"),
        ("Tuesday",   "P2", "10P/Ph2"),
        ("Tuesday",   "P4", "9P/Ph1"),
        ("Wednesday", "P1", "11P/Ph1"),
        ("Wednesday", "P5", "12P/Ph1"),
        ("Thursday",  "P3", "10P/Ph2"),
        ("Thursday",  "P5", "9P/Ph1"),
        ("Friday",    "P2", "11P/Ph1"),
        ("Friday",    "P4", "12P/Ph1"),
    ],
    "maths@greenfieldacademy.test": [
        ("Monday",    "P2", "10M/Ma1"),
        ("Monday",    "P4", "11M/Ma2"),
        ("Tuesday",   "P1", "9M/Ma1"),
        ("Tuesday",   "P3", "10M/Ma1"),
        ("Wednesday", "P2", "11M/Ma2"),
        ("Wednesday", "P4", "9M/Ma1"),
        ("Thursday",  "P1", "10M/Ma1"),
        ("Thursday",  "P4", "11M/Ma2"),
        ("Friday",    "P1", "9M/Ma1"),
        ("Friday",    "P3", "10M/Ma1"),
    ],
    "teacher1@greenfieldacademy.test": [
        ("Monday",    "P1", "7En/1"),
        ("Monday",    "P5", "8En/1"),
        ("Tuesday",   "P2", "9En/1"),
        ("Wednesday", "P3", "7En/1"),
        ("Thursday",  "P2", "8En/1"),
        ("Friday",    "P5", "9En/1"),
    ],
    "teacher2@greenfieldacademy.test": [
        ("Monday",    "P3", "8Hs/1"),
        ("Tuesday",   "P5", "9Hs/1"),
        ("Wednesday", "P1", "10Hs/1"),
        ("Thursday",  "P2", "8Hs/1"),
        ("Friday",    "P3", "9Hs/1"),
    ],
    "teacher3@greenfieldacademy.test": [
        ("Monday",    "P4", "7Sc/1"),
        ("Tuesday",   "P3", "8Sc/1"),
        ("Wednesday", "P5", "9Sc/1"),
        ("Thursday",  "P4", "10Sc/1"),
        ("Friday",    "P2", "7Sc/1"),
    ],
}

# ─── Student enrollments ───────────────────────────────────────────────────────
# One student per year-group band — enrolled in all subjects for that year.

STUDENT_ENROLLMENTS = {
    "student1@greenfieldacademy.test": ["9P/Ph1",  "9M/Ma1",  "9En/1", "9Hs/1",  "9Sc/1"],
    "student2@greenfieldacademy.test": ["10P/Ph2", "10M/Ma1",          "10Hs/1", "10Sc/1"],
    "student3@greenfieldacademy.test": ["11P/Ph1", "11M/Ma2"],
}


# ─── Helpers ───────────────────────────────────────────────────────────────────

def _sb_headers() -> Dict:
    return {
        "apikey": SERVICE_KEY,
        "Authorization": f"Bearer {SERVICE_KEY}",
        "Content-Type": "application/json",
        "Prefer": "return=representation",
    }


def _sign_in(email: str, password: str) -> str:
    r = requests.post(
        f"{SUPA_URL}/auth/v1/token?grant_type=password",
        headers={"apikey": SERVICE_KEY, "Content-Type": "application/json"},
        json={"email": email, "password": password},
    )
    r.raise_for_status()
    return r.json()["access_token"]


def _api(token: str, method: str, path: str, body: Dict = None) -> Dict:
    h = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    r = getattr(requests, method)(f"{API_BASE}{path}", headers=h, json=body)
    try:
        return r.json()
    except Exception:
        return {"_raw": r.text, "_status": r.status_code}


def _get_profile_id(email: str) -> Optional[str]:
    """Look up a profile's UUID by email via Supabase service role."""
    r = requests.get(
        f"{SUPA_URL}/rest/v1/profiles",
        headers=_sb_headers(),
        params={"email": f"eq.{email}", "select": "id", "limit": "1"},
    )
    data = r.json() if r.ok else []
    return data[0]["id"] if data else None


def _get_teacher_timetable_id(profile_id: str) -> Optional[str]:
    """Return the Supabase teacher_timetables.id for a given profile."""
    r = requests.get(
        f"{SUPA_URL}/rest/v1/teacher_timetables",
        headers=_sb_headers(),
        params={"profile_id": f"eq.{profile_id}", "select": "id", "limit": "1"},
    )
    data = r.json() if r.ok else []
    return data[0]["id"] if data else None


def _patch_slot_class_ids(teacher_tt_sb_id: str, class_code_to_id: Dict[str, str]) -> int:
    """Update class_id FK on teacher_timetable_slots rows via Supabase service role."""
    patched = 0
    for code, class_uuid in class_code_to_id.items():
        r = requests.patch(
            f"{SUPA_URL}/rest/v1/teacher_timetable_slots",
            headers=_sb_headers(),
            params={
                "teacher_timetable_id": f"eq.{teacher_tt_sb_id}",
                "subject_class": f"eq.{code}",
            },
            json={"class_id": class_uuid},
        )
        if r.ok:
            patched += 1
    return patched


# ─── Main seed ─────────────────────────────────────────────────────────────────

def seed() -> Dict[str, Any]:
    print("=" * 60)
    print("Greenfield Academy — full timetable + class + student seed")
    print("=" * 60)
    results: Dict[str, Any] = {}
    errors: List[str] = []

    # ── [1] Sign in as Greenfield admin ───────────────────────────────────────
    print("\n[1] Signing in as admin@greenfieldacademy.test...")
    try:
        admin_token = _sign_in(GREENFIELD_ADMIN_EMAIL, GREENFIELD_ADMIN_PWD)
        print("  ✓ signed in")
    except Exception as e:
        return {"success": False, "error": str(e)}

    # ── [2] POST /timetable/setup ─────────────────────────────────────────────
    print("\n[2] Setting up school timetable (academic year + terms + periods)...")
    r = _api(admin_token, "post", "/timetable/setup", {
        "year_start": "2025-09-03",
        "year_end":   "2026-07-17",
        "terms":   TERMS,
        "periods": PERIODS,
    })
    if r.get("status") == "ok" or r.get("school_timetable_id") or r.get("timetable_id"):
        print(f"  ✓ timetable: {r.get('school_timetable_id') or r.get('timetable_id')}")
        results["setup"] = "ok"
    else:
        err = f"timetable/setup: {r}"
        print(f"  ✗ {err}")
        errors.append(err)
        results["setup"] = "error"

    # ── [3] POST /timetable/materialize-periods ───────────────────────────────
    print("\n[3] Materializing academic_periods (days × periods_template)...")
    r = _api(admin_token, "post", "/timetable/materialize-periods", None)
    if r.get("status") == "ok":
        print(f"  ✓ {r.get('created')} periods created across {r.get('academic_days')} academic days")
        results["materialize_periods"] = "ok"
    else:
        err = f"materialize-periods: {r}"
        print(f"  ✗ {err}")
        errors.append(err)
        results["materialize_periods"] = "error"

    # ── [5] Build profile-ID lookup for all teachers + students ───────────────
    print("\n[3] Resolving profile IDs for teachers and students...")
    all_emails = (
        list(TEACHER_SLOTS.keys())
        + list(STUDENT_ENROLLMENTS.keys())
    )
    profile_ids: Dict[str, str] = {}
    for email in all_emails:
        pid = _get_profile_id(email)
        if pid:
            profile_ids[email] = pid
            print(f"  ✓ {email} → {pid[:8]}…")
        else:
            print(f"  ✗ profile not found for {email}")
            errors.append(f"profile_not_found: {email}")

    # ── [6] Create classes ────────────────────────────────────────────────────
    print(f"\n[4] Creating {len(CLASSES)} classes...")
    results["classes"] = {}
    class_code_to_id: Dict[str, str] = {}

    for cls in CLASSES:
        r = _api(admin_token, "post", "/database/timetable/classes", {
            "name":          cls["name"],
            "class_code":    cls["class_code"],
            "subject":       cls["subject"],
            "year_group":    cls["year_group"],
            "key_stage":     cls["key_stage"],
            "academic_year": "2025-2026",
        })
        class_id = r.get("id") or (r.get("class", {}) or {}).get("id")
        if class_id:
            class_code_to_id[cls["class_code"]] = class_id
            results["classes"][cls["class_code"]] = "ok"
            print(f"  ✓ {cls['class_code']} → {class_id[:8]}…")
        else:
            err = f"create class {cls['class_code']}: {r}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["classes"][cls["class_code"]] = "error"
        time.sleep(0.1)

    # ── [7] Add teachers to their classes ────────────────────────────────────
    print("\n[5] Adding teachers to classes...")
    results["class_teachers"] = {}
    for cls in CLASSES:
        class_id = class_code_to_id.get(cls["class_code"])
        teacher_pid = profile_ids.get(cls["teacher"])
        if not class_id or not teacher_pid:
            results["class_teachers"][cls["class_code"]] = "skip"
            continue
        r = _api(admin_token, "post", f"/database/timetable/classes/{class_id}/teachers", {
            "teacher_id": teacher_pid,
            "is_primary": True,
        })
        if r.get("status") == "ok" or r.get("id"):
            print(f"  ✓ {cls['teacher'].split('@')[0]} → {cls['class_code']}")
            results["class_teachers"][cls["class_code"]] = "ok"
        else:
            err = f"add teacher {cls['class_code']}: {r}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["class_teachers"][cls["class_code"]] = "error"
        time.sleep(0.1)

    # ── [8] Teacher timetable init + slots ────────────────────────────────────
    print("\n[6] Initialising TeacherTimetable and setting slots for each teacher...")
    results["init"] = {}
    results["slots"] = {}
    teacher_tt_sb_ids: Dict[str, str] = {}  # email → teacher_timetables.id

    for teacher_email, slot_tuples in TEACHER_SLOTS.items():
        try:
            teacher_token = _sign_in(teacher_email, PWD_TEACHER)
        except Exception as e:
            err = f"login {teacher_email}: {e}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["init"][teacher_email] = "error"
            results["slots"][teacher_email] = "error"
            continue

        # 6a: init TeacherTimetable
        r = _api(teacher_token, "post", "/timetable/init", None)
        if r.get("status") == "ok":
            print(f"  ✓ init {teacher_email}")
            results["init"][teacher_email] = "ok"
        else:
            print(f"  ~ init {teacher_email}: {r.get('message', r)} (may already exist)")
            results["init"][teacher_email] = "warn"

        # 6b: get timetable_id (Neo4j uuid_string for slot FK)
        status_r = _api(teacher_token, "get", "/timetable/status", None)
        timetable_id = status_r.get("timetable_id")
        if not timetable_id:
            err = f"no timetable_id for {teacher_email}: {status_r}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["slots"][teacher_email] = "error"
            continue

        # 6c: save slots (subject_class text; class_id patched separately)
        slot_list = [
            {
                "day_of_week":   day,
                "period_code":   code,
                "subject_class": cls,
                "start_time":    PERIOD_TIMES[code][0],
                "end_time":      PERIOD_TIMES[code][1],
            }
            for day, code, cls in slot_tuples
        ]
        r = _api(teacher_token, "post", "/timetable/slots", {
            "timetable_id": timetable_id,
            "slots": slot_list,
        })
        if r.get("status") == "ok" or r.get("created") is not None:
            count = r.get("created") or len(slot_list)
            print(f"  ✓ {teacher_email}: {count} slots")
            results["slots"][teacher_email] = "ok"
        else:
            err = f"slots {teacher_email}: {r}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["slots"][teacher_email] = "error"

        # record Supabase teacher_timetable FK for patching
        teacher_pid = profile_ids.get(teacher_email)
        if teacher_pid:
            tt_sb_id = _get_teacher_timetable_id(teacher_pid)
            if tt_sb_id:
                teacher_tt_sb_ids[teacher_email] = tt_sb_id

        time.sleep(0.3)

    # ── [9] Patch teacher_timetable_slots.class_id ────────────────────────────
    print("\n[7] Patching class_id onto teacher_timetable_slots...")
    results["slot_patch"] = {}
    for teacher_email, slot_tuples in TEACHER_SLOTS.items():
        tt_sb_id = teacher_tt_sb_ids.get(teacher_email)
        if not tt_sb_id:
            results["slot_patch"][teacher_email] = "skip"
            continue
        teacher_codes = {cls for _, _, cls in slot_tuples}
        relevant_map = {code: uid for code, uid in class_code_to_id.items() if code in teacher_codes}
        n = _patch_slot_class_ids(tt_sb_id, relevant_map)
        print(f"  ✓ {teacher_email}: {n} slots patched")
        results["slot_patch"][teacher_email] = n

    # ── [10] Enroll students in classes ───────────────────────────────────────
    print("\n[8] Enrolling students in classes...")
    results["enrollments"] = {}
    for student_email, class_codes in STUDENT_ENROLLMENTS.items():
        student_pid = profile_ids.get(student_email)
        results["enrollments"][student_email] = {}
        if not student_pid:
            results["enrollments"][student_email] = "no_profile"
            continue
        for code in class_codes:
            class_id = class_code_to_id.get(code)
            if not class_id:
                results["enrollments"][student_email][code] = "no_class"
                continue
            r = _api(admin_token, "post", f"/database/timetable/classes/{class_id}/students", {
                "student_id": student_pid,
            })
            if r.get("status") == "ok" or r.get("id"):
                print(f"  ✓ {student_email.split('@')[0]} → {code}")
                results["enrollments"][student_email][code] = "ok"
            else:
                err = f"enroll {student_email} → {code}: {r}"
                print(f"  ✗ {err}")
                errors.append(err)
                results["enrollments"][student_email][code] = "error"
            time.sleep(0.1)

    # ── [11] Materialize taught lessons ────────────────────────────────────────
    print("\n[9] Materializing taught lessons for each teacher...")
    results["materialize"] = {}
    for teacher_email in TEACHER_SLOTS:
        try:
            teacher_token = _sign_in(teacher_email, PWD_TEACHER)
        except Exception as e:
            err = f"login {teacher_email}: {e}"
            print(f"  ✗ {err}")
            errors.append(err)
            continue
        r = _api(teacher_token, "post", "/timetable/materialize", None)
        if r.get("status") == "ok":
            print(f"  ✓ {teacher_email}: {r.get('lessons_upserted', '?')} lessons, "
                  f"{r.get('whiteboard_rooms_created', '?')} rooms")
            results["materialize"][teacher_email] = "ok"
        else:
            err = f"materialize {teacher_email}: {r}"
            print(f"  ✗ {err}")
            errors.append(err)
            results["materialize"][teacher_email] = "error"
        time.sleep(0.3)

    # ── [12] Neo4j sync (B.10) ────────────────────────────────────────────────
    print("\n[10] Syncing Neo4j TaughtLesson nodes (B.10)...")
    r = _api(admin_token, "post", "/timetable/sync-lessons", None)
    if r.get("status") == "ok":
        print(f"  ✓ Neo4j sync: {r.get('taught_lessons')} lessons, "
              f"{r.get('teacher_timetables')} timetables, {r.get('slots')} slots")
        results["neo4j_sync"] = "ok"
    else:
        err = f"sync-lessons: {r}"
        print(f"  ✗ {err}")
        errors.append(err)
        results["neo4j_sync"] = "error"

    # ── Summary ───────────────────────────────────────────────────────────────
    print("\n" + "=" * 60)
    results["success"] = len(errors) == 0
    results["errors"] = errors
    if errors:
        print(f"COMPLETE with {len(errors)} error(s):")
        for e in errors:
            print(f"  ✗ {e}")
    else:
        print("COMPLETE — all steps succeeded")
    print("=" * 60)
    return results
