#!/usr/bin/env python3
"""ASUCB Open Questions — track faculty questions from course memory."""

import argparse
import hashlib
import json
import os
import re
import sys
from datetime import datetime, timezone

sys.path.insert(0, os.path.dirname(__file__))
from canvas_api import get_plugin_root, validate_course_id


QUESTION_RE = re.compile(
    r"^\s*-\s+\[\s\]\s+@(?P<owner>[^\[\s]+)"
    r"(?:\[(?P<due>\d{4}-\d{2}-\d{2})\])?\s+(?P<question>.+?)\s*$"
)


def _now_iso():
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def _course_dir(course_id):
    return os.path.join(get_plugin_root(), "courses", str(course_id))


def _questions_path(course_id):
    return os.path.join(_course_dir(course_id), "open_questions.jsonl")


def _memory_path(course_id):
    return os.path.join(_course_dir(course_id), "course-memory.md")


def _read_jsonl(path):
    if not os.path.exists(path):
        return []
    records = []
    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            try:
                records.append(json.loads(line))
            except json.JSONDecodeError:
                continue
    return records


def _write_jsonl(path, records):
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "w", encoding="utf-8") as f:
        for record in records:
            f.write(json.dumps(record, ensure_ascii=False) + "\n")


def _append_jsonl(path, records):
    if not records:
        return
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "a", encoding="utf-8") as f:
        for record in records:
            f.write(json.dumps(record, ensure_ascii=False) + "\n")


def _pending_lines(memory_text):
    in_pending = False
    for line in memory_text.splitlines():
        if re.match(r"^##\s+", line):
            in_pending = bool(re.match(r"^##\s+Pending", line, re.IGNORECASE))
            continue
        if in_pending:
            yield line


def _question_id(question):
    return hashlib.sha256(question.strip().encode("utf-8")).hexdigest()[:12]


def parse_memory_questions(course_id):
    path = _memory_path(course_id)
    if not os.path.exists(path):
        return []
    with open(path, "r", encoding="utf-8") as f:
        text = f.read()

    records = []
    for line in _pending_lines(text):
        match = QUESTION_RE.match(line)
        if not match:
            continue
        question = match.group("question").strip()
        records.append({
            "id": _question_id(question),
            "created_at": _now_iso(),
            "owner": match.group("owner"),
            "due_date": match.group("due") or None,
            "source": "memory",
            "question": question,
            "status": "open",
            "resolved_at": None,
        })
    return records


def sync_memory(course_id):
    path = _questions_path(course_id)
    existing = _read_jsonl(path)
    seen = {r.get("id") for r in existing}
    new_records = [r for r in parse_memory_questions(course_id) if r["id"] not in seen]
    _append_jsonl(path, new_records)
    return {"ok": True, "added": len(new_records), "path": path}


def _age_days(record):
    raw = record.get("created_at", "")[:10]
    try:
        created = datetime.strptime(raw, "%Y-%m-%d").replace(tzinfo=timezone.utc)
    except ValueError:
        return 0
    return (datetime.now(timezone.utc) - created).days


def list_questions(course_id, owner=None, age_gt_days=None):
    records = [r for r in _read_jsonl(_questions_path(course_id))
               if r.get("status") == "open"]
    if owner:
        wanted = owner.lstrip("@").lower()
        records = [r for r in records if str(r.get("owner", "")).lower() == wanted]
    if age_gt_days is not None:
        records = [r for r in records if _age_days(r) > age_gt_days]
    return records


def resolve_question(course_id, question_id):
    path = _questions_path(course_id)
    records = _read_jsonl(path)
    found = False
    for record in records:
        if record.get("id") == question_id:
            record["status"] = "resolved"
            record["resolved_at"] = _now_iso()
            found = True
    if not found:
        return {"ok": False, "error": f"Question id not found: {question_id}"}
    _write_jsonl(path, records)
    return {"ok": True, "resolved": question_id, "path": path}


def _print_questions(records):
    if not records:
        print("(no open questions)")
        return
    for record in records:
        due = f" due {record['due_date']}" if record.get("due_date") else ""
        created = record.get("created_at", "")[:10] or "unknown"
        print(f"{record['id']} @{record.get('owner')}{due} [{created}] {record.get('question')}")


def main():
    parser = argparse.ArgumentParser(description="Track open faculty questions")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--sync-memory", action="store_true")
    group.add_argument("--list", action="store_true")
    group.add_argument("--resolve", action="store_true")
    parser.add_argument("--course-id", required=True)
    parser.add_argument("--owner")
    parser.add_argument("--age-gt-days", type=int)
    parser.add_argument("--id", help="Question hash to resolve")
    args = parser.parse_args()
    if getattr(args, 'course_id', None) is not None:
        try:
            args.course_id = validate_course_id(args.course_id)
        except ValueError as exc:
            parser.error(str(exc))

    if args.sync_memory:
        print(json.dumps(sync_memory(args.course_id), indent=2))
    elif args.list:
        _print_questions(list_questions(args.course_id, args.owner, args.age_gt_days))
    elif args.resolve:
        if not args.id:
            parser.error("--resolve requires --id")
        result = resolve_question(args.course_id, args.id)
        print(json.dumps(result, indent=2))
        if not result["ok"]:
            sys.exit(1)


if __name__ == "__main__":
    main()
