"""Requirements traceability matrix generation.

Generates traceability matrices that map REQ-IDs to test results and coverage.
"""
from __future__ import annotations

from typing import Any


def generate_requirements_index(requirements: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """Generate requirements index from PRD requirements.

    Args:
        requirements: List of requirement dicts from PRD.

    Returns:
        List of requirement index entries with REQ-ID, title, acceptance_criteria,
        and source_prd_section.

    Example:
        >>> reqs = [
        ...     {
        ...         "id": "REQ-001",
        ...         "text": "System shall authenticate users",
        ...         "title": "User Authentication",
        ...         "acceptance": ["Given valid token, When request, Then access granted"],
        ...         "source_prd_section": "Security.Authentication"
        ...     }
        ... ]
        >>> idx = generate_requirements_index(reqs)
        >>> idx[0]["req_id"]
        'REQ-001'
    """
    from abi_spec.acceptance import parse_acceptance_criteria

    index: list[dict[str, Any]] = []

    for req in requirements:
        req_id = req.get("id", "")
        title = req.get("title", req.get("text", "")[:50])  # Fallback to first 50 chars
        acceptance_raw = req.get("acceptance", [])
        source_section = req.get("source_prd_section", "Unspecified")

        # Parse acceptance criteria into Given/When/Then structure
        acceptance_criteria = parse_acceptance_criteria(acceptance_raw)

        index.append(
            {
                "req_id": req_id,
                "title": title,
                "acceptance_criteria": acceptance_criteria,
                "source_prd_section": source_section,
            }
        )

    return index


def generate_traceability_matrix(
    requirements_index: list[dict[str, Any]],
    test_results: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Generate a requirements traceability matrix.

    Maps REQ-IDs to test IDs and their pass/fail status, and identifies
    coverage gaps.

    Args:
        requirements_index: List of requirement index entries.
        test_results: Optional dict mapping test IDs to results.
            Format: {"test_id": {"req_ids": ["REQ-001"], "status": "passed|failed|pending"}}

    Returns:
        Dict with traceability matrix data:
        {
            "matrix_version": "1.0",
            "requirements": [
                {
                    "req_id": "REQ-001",
                    "title": "...",
                    "tests": [{"test_id": "...", "status": "passed|failed|pending"}],
                    "coverage_status": "covered|uncovered",
                    "verification_status": "passed|failed|pending|untested"
                }
            ],
            "summary": {
                "total_requirements": 10,
                "covered_requirements": 8,
                "uncovered_requirements": 2,
                "passed_requirements": 6,
                "failed_requirements": 2,
                "pending_requirements": 0
            }
        }
    """
    test_results = test_results or {}

    # Build reverse mapping: REQ-ID -> list of test results
    req_to_tests: dict[str, list[dict[str, str]]] = {}

    for test_id, test_data in test_results.items():
        req_ids = test_data.get("req_ids", [])
        status = test_data.get("status", "pending")

        for req_id in req_ids:
            if req_id not in req_to_tests:
                req_to_tests[req_id] = []
            req_to_tests[req_id].append({"test_id": test_id, "status": status})

    # Build traceability matrix
    matrix_requirements: list[dict[str, Any]] = []
    covered_count = 0
    uncovered_count = 0
    passed_count = 0
    failed_count = 0
    pending_count = 0

    for req_entry in requirements_index:
        req_id = req_entry["req_id"]
        tests = req_to_tests.get(req_id, [])

        # Determine coverage and verification status
        if tests:
            coverage_status = "covered"
            covered_count += 1

            # Determine overall verification status
            test_statuses = [t["status"] for t in tests]
            if any(s == "failed" for s in test_statuses):
                verification_status = "failed"
                failed_count += 1
            elif all(s == "passed" for s in test_statuses):
                verification_status = "passed"
                passed_count += 1
            else:
                verification_status = "pending"
                pending_count += 1
        else:
            coverage_status = "uncovered"
            verification_status = "untested"
            uncovered_count += 1

        matrix_requirements.append(
            {
                "req_id": req_id,
                "title": req_entry["title"],
                "tests": tests,
                "coverage_status": coverage_status,
                "verification_status": verification_status,
            }
        )

    return {
        "matrix_version": "1.0",
        "requirements": matrix_requirements,
        "summary": {
            "total_requirements": len(requirements_index),
            "covered_requirements": covered_count,
            "uncovered_requirements": uncovered_count,
            "passed_requirements": passed_count,
            "failed_requirements": failed_count,
            "pending_requirements": pending_count,
        },
    }


def validate_req_id(req_id: str) -> bool:
    """Validate that a REQ-ID follows the correct format.

    Args:
        req_id: The requirement ID to validate.

    Returns:
        True if valid.

    Raises:
        ValueError: If the REQ-ID format is invalid.

    Example:
        >>> validate_req_id("REQ-001")
        True
        >>> validate_req_id("req-001")  # doctest: +SKIP
        ValueError: REQ-ID must match pattern ^REQ-[0-9]{3,}$
    """
    import re

    pattern = r"^REQ-[0-9]{3,}$"
    if not re.match(pattern, req_id):
        raise ValueError(f"REQ-ID must match pattern {pattern}: {req_id}")
    return True


def generate_req_id(index: int) -> str:
    """Generate a REQ-ID from an index number.

    Args:
        index: Zero-based index of the requirement.

    Returns:
        REQ-ID in format "REQ-NNN" where NNN is zero-padded to 3 digits.

    Example:
        >>> generate_req_id(0)
        'REQ-001'
        >>> generate_req_id(42)
        'REQ-043'
        >>> generate_req_id(999)
        'REQ-1000'
    """
    return f"REQ-{index + 1:03d}"
