"""Report generation for GuardRail."""

from pathlib import Path
from typing import List, Optional

from guardrail.locator import FunctionInfo


class FixPromptGenerator:
    """Generates fix prompts for failing tests."""

    @staticmethod
    def analyze_failure(failure_output: str) -> dict:
        """
        Analyze test failure output to extract key information.
        
        Returns:
            Dictionary with 'error_type', 'expected', 'actual', 'reasoning'
        """
        analysis = {
            "error_type": "unknown",
            "expected": None,
            "actual": None,
            "reasoning": "Unable to parse failure details",
        }
        
        failure_lower = failure_output.lower()
        
        # Check for type errors
        if "typeerror" in failure_lower or "type error" in failure_lower:
            analysis["error_type"] = "type_error"
            analysis["reasoning"] = "The test is using incompatible types. Check what types the function actually accepts."
        
        # Check for value errors
        elif "valueerror" in failure_lower or "value error" in failure_lower:
            analysis["error_type"] = "value_error"
            analysis["reasoning"] = "The test is using invalid values. Check what values the function actually accepts."
        
        # Check for assertion errors
        elif "assert" in failure_lower:
            analysis["error_type"] = "assertion_error"
            # Try to extract expected vs actual
            if "!=" in failure_output or "==" in failure_output:
                analysis["reasoning"] = "The test expected a different value than what the function returned. Check the function's actual behavior."
        
        # Check for attribute errors
        elif "attributeerror" in failure_lower:
            analysis["error_type"] = "attribute_error"
            analysis["reasoning"] = "The test is accessing an attribute or method that doesn't exist. Check the function's actual implementation."
        
        return analysis

    @staticmethod
    def generate_fix_prompt(
        function: FunctionInfo,
        test_code: str,
        failure_output: str,
        test_file_path: Path,
    ) -> str:
        """
        Generate a fix prompt for a failing test.

        Args:
            function: FunctionInfo object for the failing function.
            test_code: Generated test code that failed.
            failure_output: Pytest failure output.
            test_file_path: Path to the test file.

        Returns:
            Fix prompt string.
        """
        func_display = (
            f"{function.parent_class}.{function.name}"
            if function.is_method
            else function.name
        )

        # Analyze the failure
        failure_analysis = FixPromptGenerator.analyze_failure(failure_output)
        
        prompt = f"""🔧 Fix Required for Function: {func_display}

Test Failure Analysis

Function: {func_display}
Location: {function.source[:200]}...

Test File: {test_file_path}

Function Implementation:
```python
{function.source}
```

Test Code (FAILED):
```python
{test_code}
```

Failure Output:
{failure_output}

Failure Analysis:
- Error Type: {failure_analysis['error_type']}
- Reasoning: {failure_analysis['reasoning']}

CRITICAL QUESTIONS TO CONSIDER:
1. Does the test match the function's ACTUAL behavior? Read the function code carefully.
2. Are the test inputs valid for this function? Check what types the function actually accepts.
3. Is the expected value correct? Analyze what the function actually returns.
4. Should the test be fixed, or should the function be fixed?

Most likely issue: The test may be incorrect. The function code shows what it ACTUALLY does.
Compare the test expectations with the function's real implementation.

Fix Instructions:
1. FIRST: Read the function code above to understand what it actually does
2. Compare the test expectations with the function's real behavior
3. If the test is wrong (wrong types, wrong expected values), fix the test
4. If the function is wrong (doesn't match expected behavior), fix the function
5. Ensure test inputs match the function's actual parameter types
6. Re-run GuardRail after fixing

Constraints:
- Modify only this function: {func_display}
- Make all tests pass
- Don't change the function signature unless necessary
- Match the function's actual implementation, not assumptions

Test file location: {test_file_path}

After fixing, run 'guardrail run -- <your-command>' again to verify.
"""

        return prompt

    @staticmethod
    def generate_summary_report(
        total_tests: int,
        passed: bool,
        failing_tests: List[str],
        fix_prompts: List[str],
    ) -> str:
        """
        Generate a summary report of test results.

        Args:
            total_tests: Total number of tests run.
            passed: Whether all tests passed.
            failing_tests: List of failing test names.
            fix_prompts: List of fix prompts.

        Returns:
            Summary report string.
        """
        if passed:
            return f"✅ All {total_tests} test(s) passed!"

        report = f"❌ {len(failing_tests)} test(s) failed out of {total_tests}:\n\n"
        for i, (test_name, prompt) in enumerate(zip(failing_tests, fix_prompts), 1):
            report += f"{i}. {test_name}\n"
            report += f"{prompt}\n"
            report += "-" * 80 + "\n\n"

        return report

