import copy
import logging
import sys
from pathlib import Path

import pytest


REPO_ROOT = Path(__file__).resolve().parents[1]
SCRIPTS_DIR = REPO_ROOT / "scripts"
sys.path.insert(0, str(SCRIPTS_DIR))

import check_interactive_a11y
import generator


def dialog_cards_activity():
    return {
        "type": "dialog_cards",
        "title": "Dialog Cards Results",
        "filename": "dialog-cards-results.html",
        "instructions": "Review each card.",
        "cards": [
            {"front": "Term", "back": "Definition"},
            {"front": "Concept", "back": "Application"},
        ],
    }


def sequencing_activity():
    return {
        "type": "sequencing",
        "title": "Sequencing Results",
        "filename": "sequencing-results.html",
        "instructions": "Order the steps.",
        "items": [
            {"text": "First step", "position": 1},
            {"text": "Second step", "position": 2},
            {"text": "Third step", "position": 3},
        ],
        "feedback_correct": "Correct order.",
        "feedback_incorrect": "Review the canonical order.",
    }


def test_sequencing_accepts_string_items():
    """String items must be normalized to {text, position} so cards render."""
    from generator import generate_sequencing
    activity = {
        "type": "sequencing",
        "title": "String Items",
        "filename": "string-items.html",
        "instructions": "Order them.",
        "items": ["alpha", "beta", "gamma"],
        "feedback_correct": "Good.",
        "feedback_incorrect": "Retry.",
    }
    out = generate_sequencing(activity)
    assert '"text": "alpha"' in out
    assert '"position": 1' in out
    assert '"text": "gamma"' in out
    assert '"position": 3' in out


def fill_blanks_activity():
    return {
        "type": "fill_blanks",
        "title": "Fill Blanks Results",
        "filename": "fill-blanks-results.html",
        "instructions": "Complete the passage.",
        "passages": [
            {
                "segments": [
                    {"type": "text", "value": "The ASU color is "},
                    {
                        "type": "blank",
                        "answers": ["maroon"],
                        "hint": "ASU primary color",
                    },
                    {"type": "text", "value": "."},
                ],
                "feedback": "Maroon is the primary color.",
            }
        ],
    }


def branching_activity():
    return {
        "type": "branching",
        "title": "Branching Results",
        "filename": "branching-results.html",
        "instructions": "Choose the best option.",
        "nodes": [
            {
                "scenario": "A student asks for help.",
                "question": "What should you do?",
                "options": [
                    {
                        "text": "Give targeted feedback.",
                        "feedback": "This supports learning.",
                        "correct": True,
                    },
                    {
                        "text": "Ignore the request.",
                        "feedback": "This misses the support opportunity.",
                        "correct": False,
                    },
                ],
            }
        ],
        "endpoints": [
            {"minScore": 1, "title": "Strong support", "message": "Good choice."},
            {"minScore": 0, "title": "Needs review", "message": "Try again."},
        ],
    }


def quiz_activity():
    return {
        "type": "quiz",
        "title": "Quiz Results",
        "filename": "quiz-results.html",
        "instructions": "Answer each question.",
        "questions": [
            {
                "type": "mc",
                "stem": "Which color is ASU maroon?",
                "options": [
                    {"text": "#8C1D40", "correct": True, "feedback": "Correct."},
                    {"text": "#00A3E0", "correct": False, "feedback": "Not ASU maroon."},
                ],
            },
            {
                "type": "tf",
                "stem": "The activity is formative.",
                "correct": True,
                "feedback_true": "Correct.",
                "feedback_false": "It is formative.",
            },
        ],
    }


ACTIVITY_FACTORIES = {
    "dialog_cards": dialog_cards_activity,
    "sequencing": sequencing_activity,
    "fill_blanks": fill_blanks_activity,
    "branching": branching_activity,
    "quiz": quiz_activity,
}


def render_activity(activity):
    return generator.GENERATORS[activity["type"]](activity)


@pytest.mark.parametrize("activity_type", sorted(ACTIVITY_FACTORIES))
def test_download_results_enabled_adds_notes_and_download_markup(activity_type):
    activity = ACTIVITY_FACTORIES[activity_type]()
    activity["download_results"] = True

    html = render_activity(activity)

    assert 'download="results-' in html
    assert '<textarea id="download-results-notes"' in html
    assert 'aria-label="Personal notes (optional)"' in html
    assert "📄 Download my results" in html
    assert "function buildResultsBody()" in html


@pytest.mark.parametrize("activity_type", sorted(ACTIVITY_FACTORIES))
@pytest.mark.parametrize("flag_value", [False, None])
def test_download_results_disabled_or_absent_omits_button_markup(activity_type, flag_value):
    activity = ACTIVITY_FACTORIES[activity_type]()
    if flag_value is not None:
        activity["download_results"] = flag_value

    html = render_activity(activity)

    assert 'download="results-' not in html
    assert '<button type="button" class="download-results-button"' not in html
    assert '<textarea id="download-results-notes"' not in html
    assert "Download my results" not in html


@pytest.mark.parametrize("activity_type", sorted(ACTIVITY_FACTORIES))
def test_download_results_enabled_passes_interactive_a11y_check(tmp_path, activity_type):
    activity = ACTIVITY_FACTORIES[activity_type]()
    activity["download_results"] = True
    html = render_activity(activity)
    path = tmp_path / f"{activity_type}.html"
    path.write_text(html, encoding="utf-8")

    report = check_interactive_a11y.run([str(path)])

    assert report["pass"] is True
    assert report["failures"] == []
    assert ".download-results-button" in html
    assert ".download-results-notes:focus-visible" in html
    assert "outline: 3px solid var(--asu-gold)" in html


@pytest.mark.parametrize("activity_type", sorted(ACTIVITY_FACTORIES))
def test_schema_validator_accepts_download_results_and_warns_on_truthy_non_bool(
    activity_type, caplog
):
    absent = ACTIVITY_FACTORIES[activity_type]()
    present = ACTIVITY_FACTORIES[activity_type]()
    present["download_results"] = True
    coerced = ACTIVITY_FACTORIES[activity_type]()
    coerced["download_results"] = "yes"
    activities = {"m1": [copy.deepcopy(absent), copy.deepcopy(present), copy.deepcopy(coerced)]}

    with caplog.at_level(logging.WARNING):
        generator.validate_activity_schema(activities)

    assert activities["m1"][1]["download_results"] is True
    assert activities["m1"][2]["download_results"] is True
    assert "SCHEMA WARNING: m1[2] download_results should be bool" in caplog.text
    assert "unknown key 'download_results'" not in caplog.text
