"""Test multi-part comment functionality."""

import pytest

from iam_validator.core.models import PolicyValidationResult, ValidationIssue
from iam_validator.core.report import ReportGenerator


def create_large_issue(severity: str, index: int) -> ValidationIssue:
    """Create a large test validation issue."""
    return ValidationIssue(
        severity=severity,
        issue_type="TEST_ISSUE",
        message=(
            f"This is a test issue number {index} with extensive details about what went wrong. "
            * 5  # Repeat to make it larger
        ),
        statement_index=index,
        action=f"s3:GetObject{index}",
        resource=f"arn:aws:s3:::bucket-{index}/*",
        suggestion=f"Consider fixing this issue by doing XYZ for statement {index}. " * 3,
    )


def create_large_result(policy_file: str, num_issues: int) -> PolicyValidationResult:
    """Create a test validation result with large issues."""
    issues = [create_large_issue("error", i) for i in range(num_issues)]
    return PolicyValidationResult(
        policy_file=policy_file,
        is_valid=False,
        issues=issues,
    )


def test_small_report_single_part():
    """Test that small reports generate a single part."""
    generator = ReportGenerator()

    results = [create_large_result(f"policy-{i}.json", 2) for i in range(5)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report)

    assert len(parts) == 1, "Small report should generate only 1 part"
    assert "Part 1" not in parts[0], "Single part should not have part indicator"


def test_large_report_multiple_parts():
    """Test that large reports are split into multiple parts."""
    generator = ReportGenerator()

    # Create a report large enough to require splitting
    # Use smaller issues per policy so individual policies fit within limits
    results = [create_large_result(f"policy-{i}.json", 5) for i in range(50)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report, max_length_per_part=20000)

    assert len(parts) > 1, f"Large report should generate multiple parts, got {len(parts)}"
    # Parts should be reasonable - if individual policies are larger than max, that's expected
    # But we should still split at policy boundaries
    print(f"Generated {len(parts)} parts with lengths: {[len(p) for p in parts]}")
    assert all(len(part) > 0 for part in parts), "All parts should have content"


def test_first_part_has_header():
    """Test that the first part contains the summary header."""
    generator = ReportGenerator()

    results = [create_large_result(f"policy-{i}.json", 20) for i in range(50)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report, max_length_per_part=10000)

    # First part should have header
    assert "Summary" in parts[0]
    assert "Total Policies Analyzed" in parts[0]
    assert "IAM Policy Validation" in parts[0]

    # Subsequent parts should NOT have the full header
    if len(parts) > 1:
        assert "Total Policies Analyzed" not in parts[1]
        assert "Continued from previous comment" in parts[1]


def test_all_parts_have_footer():
    """Test that all parts have the footer."""
    generator = ReportGenerator()

    results = [create_large_result(f"policy-{i}.json", 20) for i in range(50)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report, max_length_per_part=10000)

    for part in parts:
        assert "Generated by IAM Policy Validator" in part
        assert "Powered by AWS IAM Access Analyzer" in part


def test_continuation_indicators():
    """Test that continuation indicators are present between parts."""
    generator = ReportGenerator()

    results = [create_large_result(f"policy-{i}.json", 20) for i in range(50)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report, max_length_per_part=10000)

    if len(parts) > 1:
        # All parts except the last should have "Continued in next comment"
        for part in parts[:-1]:
            assert "Continued in next comment" in part

        # All parts except the first should have "Continued from previous comment"
        for part in parts[1:]:
            assert "Continued from previous comment" in part


def test_errors_prioritized_across_parts():
    """Test that errors appear in earlier parts."""
    generator = ReportGenerator()

    # Create policies with errors and warnings
    results = []

    # Policies with only warnings (should appear later)
    for i in range(20):
        issues = [
            ValidationIssue(
                severity="warning",
                issue_type="WARNING",
                message=f"Warning {i}",
                statement_index=0,
            )
            for _ in range(10)
        ]
        results.append(
            PolicyValidationResult(
                policy_file=f"warning-policy-{i}.json", is_valid=False, issues=issues
            )
        )

    # Policies with errors (should appear first)
    for i in range(20):
        issues = [
            ValidationIssue(
                severity="error",
                issue_type="ERROR",
                message=f"Error {i}",
                statement_index=0,
            )
            for _ in range(10)
        ]
        results.append(
            PolicyValidationResult(
                policy_file=f"error-policy-{i}.json", is_valid=False, issues=issues
            )
        )

    report = generator.generate_report(results)
    parts = generator.generate_github_comment_parts(report, max_length_per_part=15000)

    # Verify that error policies appear before warning policies
    first_error_idx = -1
    last_warning_idx = -1

    for idx, part in enumerate(parts):
        if "error-policy-" in part and first_error_idx == -1:
            first_error_idx = idx
        if "warning-policy-" in part:
            last_warning_idx = idx

    # Errors should appear before or at the same time as warnings
    if first_error_idx >= 0 and last_warning_idx >= 0:
        assert first_error_idx <= last_warning_idx, "Errors should appear before warnings"


def test_part_limit_enforced():
    """Test that each part stays under the specified limit."""
    generator = ReportGenerator()

    results = [create_large_result(f"policy-{i}.json", 25) for i in range(100)]
    report = generator.generate_report(results)

    max_length = 20000
    parts = generator.generate_github_comment_parts(report, max_length_per_part=max_length)

    for idx, part in enumerate(parts):
        # Allow 5% buffer for calculation differences
        assert len(part) <= max_length * 1.05, (
            f"Part {idx + 1} length {len(part)} exceeds limit {max_length}"
        )


def test_no_lost_policies():
    """Test that all policies with issues are included across all parts."""
    generator = ReportGenerator()

    num_policies = 30
    results = [create_large_result(f"policy-{i}.json", 10) for i in range(num_policies)]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report, max_length_per_part=15000)

    # Count how many unique policies appear
    all_content = "\n".join(parts)
    found_policies = set()

    for i in range(num_policies):
        policy_name = f"policy-{i}.json"
        if policy_name in all_content:
            found_policies.add(policy_name)

    # All policies should be present
    assert len(found_policies) == num_policies, (
        f"Only found {len(found_policies)} policies out of {num_policies}"
    )


def test_empty_report_single_part():
    """Test that empty reports (all valid) generate a single part."""
    generator = ReportGenerator()

    results = [
        PolicyValidationResult(policy_file=f"valid-{i}.json", is_valid=True, issues=[])
        for i in range(10)
    ]
    report = generator.generate_report(results)

    parts = generator.generate_github_comment_parts(report)

    assert len(parts) == 1
    assert "All Policies Valid" in parts[0]
    assert "Part 1" not in parts[0]


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
