"""Acceptance criteria parser for Given/When/Then format.

Parses acceptance criteria strings into structured Given/When/Then format
for traceability and test generation.
"""
from __future__ import annotations

import re
from typing import Any


def parse_acceptance_criteria(acceptance: list[str]) -> dict[str, list[str]]:
    """Parse acceptance criteria strings into Given/When/Then structure.

    Supports multiple formats:
    - "Given X, When Y, Then Z"
    - "GIVEN X WHEN Y THEN Z"
    - Multiple Given/When/Then statements in a single string
    - Plain text (placed in "then" by default)

    Args:
        acceptance: List of acceptance criteria strings.

    Returns:
        Dict with "given", "when", "then" keys, each containing a list of strings.

    Examples:
        >>> parse_acceptance_criteria([
        ...     "Given valid OAuth2 token, When request is made, Then access is granted",
        ...     "Given expired token, When request is made, Then 401 is returned"
        ... ])
        {
            "given": ["valid OAuth2 token", "expired token"],
            "when": ["request is made", "request is made"],
            "then": ["access is granted", "401 is returned"]
        }
    """
    given: list[str] = []
    when: list[str] = []
    then: list[str] = []

    # Pattern to match Given/When/Then keywords (case-insensitive)
    # Matches: "Given X, When Y, Then Z" format
    gwt_pattern = re.compile(
        r"(given|when|then)\s+([^,]+?)(?=\s*,\s*(?:given|when|then)\s+|\s*$)",
        re.IGNORECASE,
    )

    for criterion in acceptance:
        # Try to parse structured Given/When/Then format
        matches = list(gwt_pattern.finditer(criterion))

        if matches:
            # Parse structured format
            for match in matches:
                keyword = match.group(1).lower()
                content = match.group(2).strip().rstrip(",")

                if keyword == "given":
                    given.append(content)
                elif keyword == "when":
                    when.append(content)
                elif keyword == "then":
                    then.append(content)
        else:
            # No structured format found, treat as plain "then" statement
            then.append(criterion.strip())

    # If no Given/When found but Then exists, add default context
    if not given and not when and then:
        given.append("system is operational")
        when.append("requirement is evaluated")

    return {"given": given, "when": when, "then": then}


def validate_acceptance_criteria(criteria: dict[str, list[str]]) -> bool:
    """Validate that acceptance criteria has all required Given/When/Then components.

    Args:
        criteria: Dict with "given", "when", "then" keys.

    Returns:
        True if valid (all sections have at least one entry).

    Raises:
        ValueError: If any section is empty.
    """
    if not criteria.get("given"):
        raise ValueError("Acceptance criteria must have at least one 'given' statement")
    if not criteria.get("when"):
        raise ValueError("Acceptance criteria must have at least one 'when' statement")
    if not criteria.get("then"):
        raise ValueError("Acceptance criteria must have at least one 'then' statement")

    return True


def format_acceptance_criteria(criteria: dict[str, list[str]]) -> str:
    """Format acceptance criteria into a human-readable string.

    Args:
        criteria: Dict with "given", "when", "then" keys.

    Returns:
        Formatted string with Given/When/Then structure.

    Example:
        >>> format_acceptance_criteria({
        ...     "given": ["valid OAuth2 token"],
        ...     "when": ["request is made"],
        ...     "then": ["access is granted"]
        ... })
        "Given valid OAuth2 token\\nWhen request is made\\nThen access is granted"
    """
    lines: list[str] = []

    for given_item in criteria.get("given", []):
        lines.append(f"Given {given_item}")

    for when_item in criteria.get("when", []):
        lines.append(f"When {when_item}")

    for then_item in criteria.get("then", []):
        lines.append(f"Then {then_item}")

    return "\n".join(lines)
