"""Parser for extracting acceptance criteria from PRD markdown."""

from __future__ import annotations

import re

from dpe.models.acceptance_criteria import AcceptanceCriteriaSection, AcceptanceCriterion


class AcceptanceCriteriaParseError(ValueError):
    """Raised when acceptance criteria cannot be parsed."""

    pass


def parse_acceptance_criteria(prd_markdown: str) -> AcceptanceCriteriaSection:
    """Parse acceptance criteria from PRD markdown.

    Expected format:
        ## Acceptance Criteria

        AC-001: [Title]
        Given: [precondition]
        When: [action]
        Then: [expected result]
        And: [additional assertion]
        And: [another assertion]

        AC-002: [Another title]
        Given: ...
        When: ...
        Then: ...

    Args:
        prd_markdown: PRD content in markdown format

    Returns:
        AcceptanceCriteriaSection containing parsed criteria

    Raises:
        AcceptanceCriteriaParseError: If section is missing or malformed
    """
    criteria_list: list[AcceptanceCriterion] = []

    # Find Acceptance Criteria section
    ac_section_pattern = r"##\s+Acceptance\s+Criteria\s*\n(.*?)(?=\n##|\Z)"
    match = re.search(ac_section_pattern, prd_markdown, re.DOTALL | re.IGNORECASE)

    if not match:
        # Section not found
        return AcceptanceCriteriaSection(criteria=[])

    section_content = match.group(1).strip()

    if not section_content:
        # Empty section
        return AcceptanceCriteriaSection(criteria=[])

    # Split by AC- markers to get individual criteria blocks
    ac_blocks = re.split(r"(?=AC-\d+:)", section_content, flags=re.IGNORECASE | re.MULTILINE)

    for block in ac_blocks:
        block = block.strip()
        if not block or not re.match(r"AC-\d+:", block, re.IGNORECASE):
            continue

        # Parse AC ID and title from first line
        lines = block.split("\n")
        first_line = lines[0]
        ac_line_match = re.match(r"(AC-\d+):\s*(.+)", first_line, re.IGNORECASE)
        if not ac_line_match:
            continue

        ac_id = ac_line_match.group(1).strip()
        title = ac_line_match.group(2).strip()

        # Parse Given, When, Then, And from the rest of the block
        given_match = re.search(r"^\s*Given:\s*(.+?)$", block, re.MULTILINE | re.IGNORECASE)
        when_match = re.search(r"^\s*When:\s*(.+?)$", block, re.MULTILINE | re.IGNORECASE)
        then_match = re.search(r"^\s*Then:\s*(.+?)$", block, re.MULTILINE | re.IGNORECASE)

        if not (given_match and when_match and then_match):
            continue

        given = given_match.group(1).strip()
        when = when_match.group(1).strip()
        then_clause = then_match.group(1).strip()

        # Parse And clauses
        and_clauses: list[str] = []
        and_matches = re.finditer(r"^\s*And:\s*(.+?)$", block, re.MULTILINE | re.IGNORECASE)
        for and_match in and_matches:
            and_clause = and_match.group(1).strip()
            and_clauses.append(and_clause)

        criterion = AcceptanceCriterion(
            ac_id=ac_id,
            title=title,
            given=given,
            when=when,
            then_clause=then_clause,
            and_clauses=and_clauses,
        )
        criteria_list.append(criterion)

    return AcceptanceCriteriaSection(criteria=criteria_list)


def validate_prd_has_acceptance_criteria(prd_markdown: str) -> tuple[bool, str]:
    """Validate that a PRD contains acceptance criteria.

    Args:
        prd_markdown: PRD content in markdown format

    Returns:
        Tuple of (is_valid, error_message)
        - is_valid: True if PRD has at least one acceptance criterion
        - error_message: Empty string if valid, error description otherwise
    """
    try:
        ac_section = parse_acceptance_criteria(prd_markdown)
    except Exception as e:
        return False, f"Failed to parse acceptance criteria: {e}"

    if not ac_section.validate_not_empty():
        return (
            False,
            "PRD validation failed: Acceptance Criteria section is missing or empty. "
            "PRDs must include at least one acceptance criterion in Given/When/Then format.",
        )

    return True, ""
