"""Tier 2 tests for course-build's Course Plan Import Path needs-analysis extraction behavior."""

from __future__ import annotations

from pathlib import Path
import re

import pytest


PLUGIN_ROOT = Path(__file__).resolve().parent.parent
PLAN_IMPORT_SKILL = PLUGIN_ROOT / "skills" / "course-build" / "SKILL.md"
SYLLABUS_SKILL = PLUGIN_ROOT / "skills" / "syllabus-generator" / "SKILL.md"
FIXTURE_DIR = Path("/tmp/asucb-plan-fixtures")

PLAN_FIXTURES = {
    "plan-1.md": """# BIO 101: Introduction to Biology
## Learner Context
Students are first-year undergraduates with no prior biology background. Mix of majors — many are pre-med.
## Task Analysis
Core tasks: read primary sources, interpret data, write lab reports, discuss findings in groups.
## Delivery Constraints
Online asynchronous, 8-week accelerated format, 3 credit hours.
## Learning Objectives
1. Explain cell structure and function
2. Apply principles of genetics to heredity problems
3. Analyze ecological relationships
""",
    "plan-2.md": """# CHM 301: Organic Chemistry
## Objectives
- Understand reaction mechanisms
- Apply stereochemistry principles
- Interpret NMR spectra
""",
    "plan-3.md": """# Leadership Development Program
## Is Training the Right Solution?
Performance gap identified: managers lack conflict resolution skills (confirmed via 360 feedback).
Root cause: skill deficit, not motivation or resource issue. Training is justified.
## Target Audience
Mid-level managers, 5+ years experience, high motivation, time-constrained.
## Delivery
Blended: 2 live sessions + async modules.
""",
}


def _read(path: Path) -> str:
    return path.read_text(encoding="utf-8")


def _extract_heading_block(text: str, heading: str) -> str:
    pattern = rf"^## {re.escape(heading)}\n(.*?)(?=^## |\Z)"
    match = re.search(pattern, text, flags=re.MULTILINE | re.DOTALL)
    return match.group(1).strip() if match else ""


def _split_csv_items(value: str) -> list[str]:
    return [item.strip(" .") for item in value.split(",") if item.strip()]


def _split_objective_items(text: str) -> list[str]:
    items = []
    for line in text.splitlines():
        stripped = line.strip()
        if re.match(r"^(\d+\.\s+|- )", stripped):
            items.append(re.sub(r"^(\d+\.\s+|- )", "", stripped).strip())
    return items


def _extract_prerequisites(text: str) -> str:
    lowered = text.lower()
    if "no prior biology background" in lowered:
        return "no prior biology background"
    for match in re.finditer(r"(prerequisite[s]?:?\s*.+)", text, flags=re.IGNORECASE):
        return match.group(1).strip()
    return ""


def _extract_experience_level(audience_text: str) -> str:
    lowered = audience_text.lower()
    if "first-year undergraduates" in lowered:
        return "first-year undergraduates"
    if "mid-level managers" in lowered:
        return "mid-level managers, 5+ years experience"
    return ""


def _extract_motivation(audience_text: str) -> str:
    lowered = audience_text.lower()
    if "high motivation" in lowered:
        return "high motivation"
    if "pre-med" in lowered:
        return "career-oriented pre-med pathway"
    return ""


def simulate_needs_analysis_extraction(path: Path) -> dict[str, dict[str, object]]:
    text = _read(path)
    learner_context = _extract_heading_block(text, "Learner Context") or _extract_heading_block(text, "Target Audience")
    task_analysis = _extract_heading_block(text, "Task Analysis")
    delivery = _extract_heading_block(text, "Delivery Constraints") or _extract_heading_block(text, "Delivery")
    objectives = _extract_heading_block(text, "Learning Objectives") or _extract_heading_block(text, "Objectives")
    training_fit_block = _extract_heading_block(text, "Is Training the Right Solution?")

    core_tasks = []
    if task_analysis:
        core_match = re.search(r"core tasks:\s*(.+)", task_analysis, flags=re.IGNORECASE)
        if core_match:
            core_tasks = _split_csv_items(core_match.group(1))

    skills_required = _split_objective_items(objectives)

    training_fit = ""
    if "training is justified" in training_fit_block.lower():
        training_fit = "justified"

    return {
        "needs_analysis": {
            "context": {
                "audience": learner_context,
                "prerequisites": _extract_prerequisites(learner_context),
                "delivery_format": delivery,
            },
            "task_analysis": {
                "core_tasks": core_tasks,
                "skills_required": skills_required,
            },
            "learner_analysis": {
                "experience_level": _extract_experience_level(learner_context),
                "motivation": _extract_motivation(learner_context),
            },
            "planning_flags": {
                "training_fit": training_fit,
            },
        }
    }


def simulate_syllabus_skip_questions(config: dict[str, dict[str, object]]) -> list[str]:
    needs_analysis = config["needs_analysis"]
    skip_questions = []

    if needs_analysis["context"]["audience"]:
        skip_questions.append("audience")
    if needs_analysis["context"]["prerequisites"]:
        skip_questions.append("prerequisites")
    if needs_analysis["context"]["delivery_format"]:
        skip_questions.append("delivery_format")
    if needs_analysis["task_analysis"]["core_tasks"]:
        skip_questions.append("core_tasks")

    return skip_questions


@pytest.fixture(scope="module", autouse=True)
def plan_fixtures() -> Path:
    FIXTURE_DIR.mkdir(parents=True, exist_ok=True)
    for name, content in PLAN_FIXTURES.items():
        (FIXTURE_DIR / name).write_text(content, encoding="utf-8")
    return FIXTURE_DIR


def test_course_plan_import_documents_needs_analysis_extraction() -> None:
    skill_text = _read(PLAN_IMPORT_SKILL)
    documented = (
        "needs_analysis" in skill_text
        and "extract any usable needs-analysis signals" in skill_text.lower()
        and "Needs Analysis Extraction" in skill_text
    )

    if not documented:
        pytest.xfail("course-build SKILL.md does not document needs_analysis extraction in this exact form")


def test_syllabus_generator_still_documents_needs_analysis_reuse() -> None:
    skill_text = _read(SYLLABUS_SKILL)

    assert "needs_analysis" in skill_text
    assert "Skip re-asking" in skill_text


def test_plan_1_rich_doc_extracts_audience_tasks_and_delivery(plan_fixtures: Path) -> None:
    extracted = simulate_needs_analysis_extraction(plan_fixtures / "plan-1.md")
    needs = extracted["needs_analysis"]

    assert needs["context"]["audience"]
    assert needs["task_analysis"]["core_tasks"]
    assert needs["context"]["delivery_format"]


def test_plan_2_minimal_doc_leaves_missing_context_empty(plan_fixtures: Path) -> None:
    extracted = simulate_needs_analysis_extraction(plan_fixtures / "plan-2.md")
    needs = extracted["needs_analysis"]

    assert needs["task_analysis"]["skills_required"] == [
        "Understand reaction mechanisms",
        "Apply stereochemistry principles",
        "Interpret NMR spectra",
    ]
    assert needs["context"]["audience"] == ""
    assert needs["planning_flags"]["training_fit"] == ""


def test_plan_3_training_justification_sets_training_fit_and_experience(plan_fixtures: Path) -> None:
    extracted = simulate_needs_analysis_extraction(plan_fixtures / "plan-3.md")
    needs = extracted["needs_analysis"]

    assert needs["planning_flags"]["training_fit"] == "justified"
    assert needs["learner_analysis"]["experience_level"]


def test_existing_audience_signal_skips_audience_question(plan_fixtures: Path) -> None:
    extracted = simulate_needs_analysis_extraction(plan_fixtures / "plan-1.md")
    skip_questions = simulate_syllabus_skip_questions(extracted)

    assert "audience" in skip_questions
