#!/usr/bin/env python3
"""Tests for foundation_accessibility_audit.py — verifies WCAG checks."""

import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))

from foundation_accessibility_audit import (
    A11yHTMLParser, Severity, A11yViolation,
    parse_color, contrast_ratio, relative_luminance,
    run_programmatic_checks, check_page_title, check_images_alt_text,
    check_heading_hierarchy, check_lang_attribute, check_landmarks,
    check_skip_nav, check_form_labels, check_link_text,
    _parse_json_response, format_report, A11yAuditReport, A11yPageResult,
)


# === Color Utilities ===

def test_parse_color_hex6():
    assert parse_color("#ff0000") == (255, 0, 0)
    assert parse_color("#000000") == (0, 0, 0)
    assert parse_color("#ffffff") == (255, 255, 255)
    print("  PASS: test_parse_color_hex6")


def test_parse_color_hex3():
    assert parse_color("#f00") == (255, 0, 0)
    assert parse_color("#abc") == (170, 187, 204)
    print("  PASS: test_parse_color_hex3")


def test_parse_color_rgb():
    assert parse_color("rgb(255, 0, 0)") == (255, 0, 0)
    assert parse_color("rgb( 128 , 64 , 32 )") == (128, 64, 32)
    print("  PASS: test_parse_color_rgb")


def test_parse_color_named():
    assert parse_color("white") == (255, 255, 255)
    assert parse_color("black") == (0, 0, 0)
    print("  PASS: test_parse_color_named")


def test_parse_color_invalid():
    assert parse_color("not-a-color") is None
    assert parse_color("") is None
    print("  PASS: test_parse_color_invalid")


def test_contrast_ratio_black_white():
    ratio = contrast_ratio((0, 0, 0), (255, 255, 255))
    assert ratio > 20  # Should be 21:1
    print(f"  PASS: test_contrast_ratio_black_white ({ratio:.1f}:1)")


def test_contrast_ratio_same():
    ratio = contrast_ratio((128, 128, 128), (128, 128, 128))
    assert ratio == 1.0
    print("  PASS: test_contrast_ratio_same")


def test_contrast_ratio_wcag_aa():
    # #767676 on white = 4.54:1 (WCAG AA pass for normal text)
    ratio = contrast_ratio((118, 118, 118), (255, 255, 255))
    assert ratio >= 4.5
    print(f"  PASS: test_contrast_ratio_wcag_aa ({ratio:.2f}:1)")


# === HTML Parser ===

def test_parser_title():
    parser = A11yHTMLParser()
    parser.feed("<html><head><title>Test Page</title></head></html>")
    assert parser.title == "Test Page"
    print("  PASS: test_parser_title")


def test_parser_images():
    parser = A11yHTMLParser()
    parser.feed('<html><body><img src="a.png" alt="Alt text"><img src="b.png"></body></html>')
    assert len(parser.images) == 2
    assert parser.images[0]["alt"] == "Alt text"
    assert parser.images[1]["alt"] is None
    print("  PASS: test_parser_images")


def test_parser_headings():
    parser = A11yHTMLParser()
    parser.feed("<html><body><h1>Main</h1><h2>Sub</h2><h4>Skip</h4></body></html>")
    assert len(parser.headings) == 3
    assert parser.headings[0] == {"level": 1, "text": "Main"}
    assert parser.headings[2] == {"level": 4, "text": "Skip"}
    print("  PASS: test_parser_headings")


def test_parser_lang():
    parser = A11yHTMLParser()
    parser.feed('<html lang="en"><body></body></html>')
    assert parser.lang == "en"
    print("  PASS: test_parser_lang")


def test_parser_landmarks():
    parser = A11yHTMLParser()
    parser.feed("<html><body><nav>Links</nav><main>Content</main></body></html>")
    tags = {lm["tag"] for lm in parser.landmarks}
    assert "nav" in tags
    assert "main" in tags
    print("  PASS: test_parser_landmarks")


# === Programmatic Checks ===

def test_check_page_title_empty():
    parser = A11yHTMLParser()
    parser.title = ""
    violations = check_page_title(parser)
    assert len(violations) == 1
    assert violations[0].criterion == "2.4.2"
    assert violations[0].severity == Severity.MAJOR
    print("  PASS: test_check_page_title_empty")


def test_check_page_title_present():
    parser = A11yHTMLParser()
    parser.title = "My Great Page"
    violations = check_page_title(parser)
    assert len(violations) == 0
    print("  PASS: test_check_page_title_present")


def test_check_lang_missing():
    parser = A11yHTMLParser()
    parser.lang = ""
    violations = check_lang_attribute(parser)
    assert len(violations) == 1
    assert violations[0].criterion == "3.1.1"
    print("  PASS: test_check_lang_missing")


def test_check_images_missing_alt():
    parser = A11yHTMLParser()
    parser.images = [{"src": "photo.jpg", "alt": None}]
    violations = check_images_alt_text(parser)
    assert len(violations) == 1
    assert violations[0].severity == Severity.CRITICAL
    print("  PASS: test_check_images_missing_alt")


def test_check_images_with_alt():
    parser = A11yHTMLParser()
    parser.images = [{"src": "photo.jpg", "alt": "A photo"}]
    violations = check_images_alt_text(parser)
    assert len(violations) == 0
    print("  PASS: test_check_images_with_alt")


def test_check_images_decorative():
    parser = A11yHTMLParser()
    parser.images = [{"src": "deco.png", "alt": "", "role": "presentation"}]
    violations = check_images_alt_text(parser)
    assert len(violations) == 0
    print("  PASS: test_check_images_decorative")


def test_check_headings_no_h1():
    parser = A11yHTMLParser()
    parser.headings = [{"level": 2, "text": "Sub"}, {"level": 3, "text": "Sub sub"}]
    violations = check_heading_hierarchy(parser)
    assert any(v.criterion == "1.3.1" and "h1" in v.description.lower() for v in violations)
    print("  PASS: test_check_headings_no_h1")


def test_check_headings_skip():
    parser = A11yHTMLParser()
    parser.headings = [{"level": 1, "text": "Main"}, {"level": 4, "text": "Skipped"}]
    violations = check_heading_hierarchy(parser)
    assert any("skipped" in v.description.lower() for v in violations)
    print("  PASS: test_check_headings_skip")


def test_check_skip_nav_missing():
    parser = A11yHTMLParser()
    parser.skip_nav = False
    parser.links = [{"text": "Home", "href": "/"}, {"text": "About", "href": "/about"}]
    violations = check_skip_nav(parser)
    assert len(violations) == 1
    assert violations[0].criterion == "2.4.1"
    print("  PASS: test_check_skip_nav_missing")


def test_check_link_text_empty():
    parser = A11yHTMLParser()
    parser.links = [{"text": "", "href": "/page", "aria_label": ""}]
    violations = check_link_text(parser)
    assert len(violations) == 1
    assert violations[0].criterion == "2.4.4"
    print("  PASS: test_check_link_text_empty")


def test_check_link_text_generic():
    parser = A11yHTMLParser()
    parser.links = [{"text": "Click here", "href": "/page"}]
    violations = check_link_text(parser)
    assert any("non-descriptive" in v.description.lower() for v in violations)
    print("  PASS: test_check_link_text_generic")


def test_run_programmatic_checks_full():
    html = """<!DOCTYPE html>
<html lang="en">
<head><title>Good Page</title></head>
<body>
<nav><a href="#main">Skip to content</a></nav>
<main>
<h1>Welcome</h1>
<h2>Section</h2>
<img src="hero.jpg" alt="Hero image">
<a href="/about">About Us</a>
</main>
</body>
</html>"""
    violations = run_programmatic_checks(html)
    # This page should have very few or no violations
    criticals = [v for v in violations if v.severity == Severity.CRITICAL]
    assert len(criticals) == 0
    print(f"  PASS: test_run_programmatic_checks_full ({len(violations)} minor issues)")


# === JSON Parsing ===

def test_parse_json_clean():
    result = _parse_json_response('{"violations": [], "overall_score": 100}')
    assert result["overall_score"] == 100
    print("  PASS: test_parse_json_clean")


def test_parse_json_fenced():
    result = _parse_json_response('```json\n{"overall_score": 80}\n```')
    assert result["overall_score"] == 80
    print("  PASS: test_parse_json_fenced")


# === Formatting ===

def test_format_json():
    report = A11yAuditReport(site="test.com", pages_audited=1, overall_score=90)
    output = format_report(report, "json")
    parsed = json.loads(output)
    assert parsed["site"] == "test.com"
    assert parsed["overall_score"] == 90
    print("  PASS: test_format_json")


def test_format_text():
    report = A11yAuditReport(site="test.com", pages_audited=1, overall_score=90,
                              summary="Test complete")
    output = format_report(report, "text")
    assert "ACCESSIBILITY AUDIT" in output
    assert "test.com" in output
    print("  PASS: test_format_text")


# === Run All ===

def run_all():
    print("=== foundation_accessibility_audit tests ===")
    tests = [
        test_parse_color_hex6, test_parse_color_hex3, test_parse_color_rgb,
        test_parse_color_named, test_parse_color_invalid,
        test_contrast_ratio_black_white, test_contrast_ratio_same, test_contrast_ratio_wcag_aa,
        test_parser_title, test_parser_images, test_parser_headings,
        test_parser_lang, test_parser_landmarks,
        test_check_page_title_empty, test_check_page_title_present,
        test_check_lang_missing,
        test_check_images_missing_alt, test_check_images_with_alt, test_check_images_decorative,
        test_check_headings_no_h1, test_check_headings_skip,
        test_check_skip_nav_missing,
        test_check_link_text_empty, test_check_link_text_generic,
        test_run_programmatic_checks_full,
        test_parse_json_clean, test_parse_json_fenced,
        test_format_json, test_format_text,
    ]
    passed = 0
    failed = 0
    for test in tests:
        try:
            test()
            passed += 1
        except Exception as e:
            print(f"  FAIL: {test.__name__} — {e}")
            failed += 1
    print(f"\n{'ALL PASSED' if failed == 0 else f'{failed} FAILED'}: {passed}/{len(tests)}")
    return failed == 0


if __name__ == "__main__":
    sys.exit(0 if run_all() else 1)
