"""Tests for acceptance criteria parsing."""
import pytest

from abi_spec.acceptance import (
    format_acceptance_criteria,
    parse_acceptance_criteria,
    validate_acceptance_criteria,
)


class TestParseAcceptanceCriteria:
    def test_parse_structured_given_when_then(self):
        acceptance = [
            "Given valid OAuth2 token, When request is made, Then access is granted"
        ]

        result = parse_acceptance_criteria(acceptance)

        assert "given" in result
        assert "when" in result
        assert "then" in result
        assert "valid OAuth2 token" in result["given"]
        assert "request is made" in result["when"]
        assert "access is granted" in result["then"]

    def test_parse_multiple_criteria(self):
        acceptance = [
            "Given valid token, When request made, Then access granted",
            "Given expired token, When request made, Then 401 returned",
        ]

        result = parse_acceptance_criteria(acceptance)

        assert len(result["given"]) == 2
        assert len(result["when"]) == 2
        assert len(result["then"]) == 2
        assert "valid token" in result["given"]
        assert "expired token" in result["given"]

    def test_parse_case_insensitive(self):
        acceptance = ["GIVEN valid token, WHEN request made, THEN access granted"]

        result = parse_acceptance_criteria(acceptance)

        assert "valid token" in result["given"]
        assert "request made" in result["when"]
        assert "access granted" in result["then"]

    def test_parse_plain_text_as_then(self):
        """Test that plain text without Given/When/Then is treated as 'then'."""
        acceptance = ["Valid OAuth2 token grants access", "Expired token returns 401"]

        result = parse_acceptance_criteria(acceptance)

        assert len(result["then"]) == 2
        assert "Valid OAuth2 token grants access" in result["then"]
        assert "Expired token returns 401" in result["then"]
        # Should add default given/when
        assert len(result["given"]) > 0
        assert len(result["when"]) > 0

    def test_parse_mixed_format(self):
        """Test parsing mixed structured and plain text."""
        acceptance = [
            "Given valid token, When request made, Then access granted",
            "API response includes X-Request-ID header",
        ]

        result = parse_acceptance_criteria(acceptance)

        assert "valid token" in result["given"]
        assert "request made" in result["when"]
        assert "access granted" in result["then"]
        assert "API response includes X-Request-ID header" in result["then"]

    def test_parse_empty_acceptance(self):
        acceptance = []

        result = parse_acceptance_criteria(acceptance)

        assert result["given"] == []
        assert result["when"] == []
        assert result["then"] == []

    def test_parse_whitespace_handling(self):
        acceptance = [
            "  Given   valid token  ,  When   request made  ,  Then   access granted  "
        ]

        result = parse_acceptance_criteria(acceptance)

        assert "valid token" in result["given"]
        assert "request made" in result["when"]
        assert "access granted" in result["then"]


class TestValidateAcceptanceCriteria:
    def test_validate_complete_criteria(self):
        criteria = {
            "given": ["valid token"],
            "when": ["request made"],
            "then": ["access granted"],
        }

        assert validate_acceptance_criteria(criteria) is True

    def test_validate_missing_given(self):
        criteria = {"given": [], "when": ["request made"], "then": ["access granted"]}

        with pytest.raises(ValueError, match="at least one 'given' statement"):
            validate_acceptance_criteria(criteria)

    def test_validate_missing_when(self):
        criteria = {"given": ["valid token"], "when": [], "then": ["access granted"]}

        with pytest.raises(ValueError, match="at least one 'when' statement"):
            validate_acceptance_criteria(criteria)

    def test_validate_missing_then(self):
        criteria = {"given": ["valid token"], "when": ["request made"], "then": []}

        with pytest.raises(ValueError, match="at least one 'then' statement"):
            validate_acceptance_criteria(criteria)

    def test_validate_multiple_statements(self):
        criteria = {
            "given": ["valid token", "authenticated user"],
            "when": ["request made", "API called"],
            "then": ["access granted", "response returned"],
        }

        assert validate_acceptance_criteria(criteria) is True


class TestFormatAcceptanceCriteria:
    def test_format_basic(self):
        criteria = {
            "given": ["valid token"],
            "when": ["request made"],
            "then": ["access granted"],
        }

        result = format_acceptance_criteria(criteria)

        assert "Given valid token" in result
        assert "When request made" in result
        assert "Then access granted" in result

    def test_format_multiple_statements(self):
        criteria = {
            "given": ["valid token", "authenticated user"],
            "when": ["request made"],
            "then": ["access granted", "response returned"],
        }

        result = format_acceptance_criteria(criteria)

        assert "Given valid token" in result
        assert "Given authenticated user" in result
        assert "When request made" in result
        assert "Then access granted" in result
        assert "Then response returned" in result

    def test_format_preserves_order(self):
        criteria = {
            "given": ["A", "B"],
            "when": ["C"],
            "then": ["D", "E"],
        }

        result = format_acceptance_criteria(criteria)
        lines = result.split("\n")

        assert lines[0] == "Given A"
        assert lines[1] == "Given B"
        assert lines[2] == "When C"
        assert lines[3] == "Then D"
        assert lines[4] == "Then E"

    def test_format_empty_sections(self):
        criteria = {"given": [], "when": [], "then": []}

        result = format_acceptance_criteria(criteria)

        assert result == ""


class TestRoundTrip:
    def test_parse_format_round_trip(self):
        """Test that parsing and formatting are consistent."""
        original = [
            "Given valid OAuth2 token, When request is made, Then access is granted"
        ]

        parsed = parse_acceptance_criteria(original)
        formatted = format_acceptance_criteria(parsed)

        # Parse again using line-by-line format (since format_acceptance_criteria outputs multi-line)
        reparsed = parse_acceptance_criteria(formatted.split("\n"))

        assert parsed["given"] == reparsed["given"]
        assert parsed["when"] == reparsed["when"]
        assert parsed["then"] == reparsed["then"]
