#!/usr/bin/env python3
"""ASUCB Init Course Memory — create a stub course-memory.md on first session lock.

Usage:
    python3 scripts/init_course_memory.py --course-id ID [--force]
    python3 scripts/init_course_memory.py --from-handoff PATH [--force]

Pulls course metadata from Canvas API (name, course_code, term, role).
Falls back to courses/registry.json if Canvas call fails.
Refuses to overwrite an existing file unless --force is passed.
Exit 0 on success; exit 1 only if neither Canvas nor registry has the course.
"""

import argparse
import json
import os
import sys
from datetime import date

sys.path.insert(0, os.path.dirname(__file__))

try:
    from dotenv import load_dotenv
    load_dotenv(os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env"))
except ImportError:
    pass

from canvas_api import get_plugin_root, validate_course_id


TEMPLATE = """\
---
course: {course_name}
courseId: "{course_id}"
canvas_code: {canvas_code}
term: {term}
faculty: unknown
instructional_designer: unknown
last_active: {today}
---

## Faculty Preferences

_none yet — populate during session as instructor preferences emerge_

## Design Decisions

## Current State

Course locked for first session. No work yet.

## Build History

## Notes

## Pending

### Can do now

### Blocked — need instructor input
"""


def _fetch_canvas_meta(course_id):
    """Return (name, code, term) from Canvas API, or raise on failure."""
    import os
    import requests

    token = os.environ.get("CANVAS_TOKEN")
    domain = os.environ.get("CANVAS_DOMAIN", "canvas.asu.edu")
    if not token:
        raise RuntimeError("CANVAS_TOKEN not set")

    url = f"https://{domain}/api/v1/courses/{course_id}"
    params = {"include[]": ["term", "enrollments"]}
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(url, headers=headers, params=params, timeout=15)
    resp.raise_for_status()
    data = resp.json()

    name = data.get("name", f"Course {course_id}")
    code = data.get("course_code", "")
    term = (data.get("term") or {}).get("name", "unknown")
    return name, code, term


def _fetch_registry_meta(course_id):
    """Return (name, code) from courses/registry.json, or raise on failure."""
    registry_path = os.path.join(get_plugin_root(), "courses", "registry.json")
    if not os.path.exists(registry_path):
        raise FileNotFoundError("registry.json not found")
    with open(registry_path, "r", encoding="utf-8") as f:
        registry = json.load(f)
    courses = registry if isinstance(registry, list) else registry.get("courses", [])
    for c in courses:
        if str(c.get("id")) == str(course_id):
            return c.get("name", f"Course {course_id}"), c.get("code", "")
    raise KeyError(f"Course {course_id} not found in registry")


def _parse_frontmatter(text):
    """Return (meta_dict, body_text) from simple YAML frontmatter."""
    meta = {}
    body = text
    if text.startswith("---"):
        end = text.find("\n---", 3)
        if end != -1:
            for line in text[3:end].strip().splitlines():
                if ":" in line:
                    _pf_key = line.split(":", 1)
                    key = _pf_key[0].strip() if _pf_key else ""
                    value = _pf_key[1].strip() if len(_pf_key) > 1 else ""
                    meta[key.strip()] = value.strip().strip('"').strip("'")
            body = text[end + 4:].lstrip("\n")
    return meta, body


def _split_sections(body):
    """Return mapping of top-level ## heading text to section body."""
    sections = {}
    current = None
    lines = []
    for line in body.splitlines():
        if line.startswith("## "):
            if current is not None:
                sections[current] = "\n".join(lines).strip()
            current = line[3:].strip()
            lines = []
        elif current is not None:
            lines.append(line)
    if current is not None:
        sections[current] = "\n".join(lines).strip()
    return sections


def _parse_course_meta(section):
    """Parse '- **key**: value' or '- key: value' Course Meta bullets."""
    meta = {}
    for line in section.splitlines():
        text = line.strip()
        if text.startswith("- "):
            text = text[2:].strip()
        text = text.replace("**", "")
        if ":" in text:
            _pf_key = text.split(":", 1)
            key = _pf_key[0].strip() if _pf_key else ""
            value = _pf_key[1].strip() if len(_pf_key) > 1 else ""
            meta[key.strip()] = value.strip()
    return meta


def _section_or_default(sections, name, default=""):
    value = sections.get(name, "").strip()
    return value if value else default


def _memory_from_handoff(handoff_path, force=False):
    """Create course-memory.md from a generated handoff Markdown file."""
    with open(handoff_path, "r", encoding="utf-8") as f:
        text = f.read()
    handoff_meta, body = _parse_frontmatter(text)
    sections = _split_sections(body)
    course_meta = _parse_course_meta(sections.get("Course Meta", ""))

    course_id = handoff_meta.get("courseId") or handoff_meta.get("course_id")
    if not course_id:
        print("[init_course_memory] ERROR: handoff frontmatter missing courseId.")
        sys.exit(1)

    course_dir = os.path.join(get_plugin_root(), "courses", str(course_id))
    dest = os.path.join(course_dir, "course-memory.md")
    if os.path.exists(dest) and not force:
        print(f"[init_course_memory] ERROR: {dest} already exists. Use --force to overwrite.")
        sys.exit(1)

    course_name = (
        handoff_meta.get("course")
        or course_meta.get("course")
        or course_meta.get("name")
        or f"Course {course_id}"
    )
    pending = sections.get("Outstanding Pending", "").strip()
    pending_text = pending if pending else "### Can do now\n\n### Blocked — need instructor input"
    content = f"""\
---
course: {course_name}
courseId: "{course_id}"
canvas_code: {course_meta.get("canvas_code") or course_meta.get("course_code") or "unknown"}
term: {course_meta.get("term") or course_meta.get("session") or "unknown"}
faculty: {course_meta.get("faculty") or "unknown"}
instructional_designer: {course_meta.get("instructional_designer") or "unknown"}
last_active: {date.today().isoformat()}
---

## Faculty Preferences

{_section_or_default(sections, "Faculty Preferences", "_none yet — populate during session as instructor preferences emerge_")}

## Design Decisions

{_section_or_default(sections, "Design Decisions")}

## Current State

{_section_or_default(sections, "Current State", "Course memory restored from handoff.")}

## Build History

{_section_or_default(sections, "Build History")}

## Notes

{_section_or_default(sections, "Notes")}

## Pending

{pending_text}
"""
    os.makedirs(course_dir, exist_ok=True)
    with open(dest, "w", encoding="utf-8") as f:
        f.write(content)
    print(f"[init_course_memory] Written from handoff: {dest}")



def _init_single_course(course_id, force=False):
    """Init course memory for a single course ID. Returns True if written."""
    course_id = str(course_id)
    course_dir = os.path.join(get_plugin_root(), "courses", course_id)
    dest = os.path.join(course_dir, "course-memory.md")

    if os.path.exists(dest) and not force:
        print(f"[init_course_memory] Skipping {course_id} — {dest} already exists.")
        return False

    name, code, term = None, None, None
    canvas_ok = False
    try:
        name, code, term = _fetch_canvas_meta(course_id)
        canvas_ok = True
    except Exception as exc:
        print(f"[init_course_memory] WARNING: Canvas fetch failed for {course_id} ({exc}); trying registry.")

    if not canvas_ok:
        try:
            name, code = _fetch_registry_meta(course_id)
            term = "unknown"
        except Exception as exc2:
            print(f"[init_course_memory] ERROR: Registry fallback also failed for {course_id} ({exc2}).")
            return False

    os.makedirs(course_dir, exist_ok=True)
    stub = TEMPLATE.format(
        course_name=name,
        course_id=course_id,
        canvas_code=code or "unknown",
        term=term or "unknown",
        today=date.today().isoformat(),
    )
    with open(dest, "w", encoding="utf-8") as f:
        f.write(stub)
    print(f"[init_course_memory] Written: {dest}")
    return True


def main():
    parser = argparse.ArgumentParser(description="Create stub course-memory.md")
    parser.add_argument("--course-id", help="Canvas course ID")
    parser.add_argument("--from-handoff", help="Create memory from handoff Markdown")
    parser.add_argument("--all", action="store_true",
                        help="Init memory for all registry courses missing a stub")
    parser.add_argument("--force", action="store_true", help="Overwrite if file exists")
    parser.add_argument("--archive", action="store_true",
                        help="Set status: archived in existing memory frontmatter")
    parser.add_argument("--unarchive", action="store_true",
                        help="Set status: active in existing memory frontmatter")
    args = parser.parse_args()

    if args.course_id is not None:
        try:
            args.course_id = validate_course_id(args.course_id)
        except ValueError as exc:
            parser.error(str(exc))

    # Archive / unarchive flow — operates on existing memory file
    if args.archive or args.unarchive:
        if not args.course_id:
            parser.error("--archive / --unarchive require --course-id")
        target = "archived" if args.archive else "active"
        path = os.path.join(get_plugin_root(), "courses", str(args.course_id), "course-memory.md")
        if not os.path.exists(path):
            print(f"[init_course_memory] ERROR: {path} not found.")
            sys.exit(1)
        with open(path, "r", encoding="utf-8") as f:
            text = f.read()
        meta, body = _parse_frontmatter(text)
        meta["status"] = target
        # Rebuild frontmatter
        lines = ["---"]
        for k, v in meta.items():
            lines.append(f"{k}: {v}")
        lines.append("---")
        lines.append("")
        new_text = "\n".join(lines) + "\n" + body.lstrip("\n")
        with open(path, "w", encoding="utf-8") as f:
            f.write(new_text)
        print(f"[init_course_memory] Course {args.course_id} status set to '{target}'")
        sys.exit(0)

    if args.from_handoff:
        _memory_from_handoff(args.from_handoff, force=args.force)
        sys.exit(0)

    if args.all:
        registry_path = os.path.join(get_plugin_root(), "courses", "registry.json")
        if not os.path.exists(registry_path):
            print("[init_course_memory] ERROR: courses/registry.json not found.")
            sys.exit(1)
        with open(registry_path, "r", encoding="utf-8") as f:
            registry = json.load(f)
        courses = registry if isinstance(registry, list) else registry.get("courses", [])
        written = 0
        skipped = 0
        for c in courses:
            cid = str(c.get("id") or c) if isinstance(c, dict) else str(c)
            try:
                cid = validate_course_id(cid)
            except ValueError:
                continue
            ok = _init_single_course(cid, force=args.force)
            if ok:
                written += 1
            else:
                skipped += 1
        print(f"[init_course_memory] --all done: {written} written, {skipped} skipped.")
        sys.exit(0)

    if not args.course_id:
        parser.error("--course-id is required unless --from-handoff or --all is used")

    course_id = str(args.course_id)
    ok = _init_single_course(course_id, force=args.force)
    if not ok and not os.path.exists(
        os.path.join(get_plugin_root(), "courses", course_id, "course-memory.md")
    ):
        sys.exit(1)
    sys.exit(0)


if __name__ == "__main__":
    main()
