"""
Jest Configuration Generator.

Generates jest.config.js configuration files for JavaScript/TypeScript projects
with test classification patterns based on the universal test taxonomy defined
in config/test_taxonomy.py.

This solves **missing test classification in Jest projects** which causes:
- No standardized way to run specific test types (only unit tests, only security tests)
- Inconsistent test naming across JavaScript projects
- Manual test filtering instead of framework-supported patterns
- No guidance for developers on test classification

Jest doesn't have native marker support like pytest, so the generator uses
**test name patterns** and **comment-based classification** approaches:
1. Test name patterns: describe('[unit][functional]', ...)
2. Comment annotations: // @test-level: unit, @test-type: functional

The generator creates jest.config.js with:
1. Test discovery settings (testMatch patterns)
2. Example patterns for all test levels (unit, integration, system, etc.)
3. Example patterns for all test types (functional, security, performance, etc.)
4. Example patterns for all modifiers (slow, requires-db, etc.)
5. Helpful comments explaining classification approaches
6. Coverage thresholds and best practices

Usage:
    from cli.config_generators.jest_generator import JestConfigGenerator

    generator = JestConfigGenerator()
    jest_config_content = generator.generate_jest_config(Path("/path/to/project"))

    # Write to file
    with open("jest.config.js", "w", encoding="utf-8") as f:
        f.write(jest_config_content)
"""

from pathlib import Path
from typing import Optional

from config.test_taxonomy import (
    TEST_TAXONOMY,
    get_test_levels,
    get_test_types,
    get_modifiers,
    get_test_level_description,
    get_test_type_description,
    get_modifier_description,
)


class JestConfigGenerator:
    """
    Generate jest.config.js configuration files with test taxonomy patterns.

    Responsibilities:
    - Generate jest.config.js with test classification pattern examples
    - Include standard Jest configuration (testMatch, coverage, etc.)
    - Provide helpful comments explaining classification approaches
    - Support customization via project configuration (future)

    Example:
        >>> generator = JestConfigGenerator()
        >>> content = generator.generate_jest_config(Path("/my/project"))
        >>> print(content)
        // jest.config.js - Jest configuration with test classification patterns
        // Generated by Trustable AI framework (trustable-ai init)
        ...
    """

    def __init__(self) -> None:
        """Initialize Jest configuration generator."""
        pass

    def generate_jest_config(
        self,
        project_path: Path,
        test_match: Optional[list] = None,
        coverage_threshold: Optional[int] = None,
    ) -> str:
        """
        Generate jest.config.js configuration file content.

        Args:
            project_path: Path to the project directory (used for path resolution)
            test_match: Custom test file patterns (default: standard Jest patterns)
            coverage_threshold: Coverage percentage threshold (default: 80)

        Returns:
            String content of jest.config.js file ready to write

        Example:
            >>> generator = JestConfigGenerator()
            >>> content = generator.generate_jest_config(Path("/my/project"))
            >>> assert "module.exports" in content
            >>> assert "[unit]" in content
        """
        # Use defaults if not provided
        if test_match is None:
            test_match = [
                "**/__tests__/**/*.[jt]s?(x)",
                "**/?(*.)+(spec|test).[jt]s?(x)"
            ]
        coverage_threshold = coverage_threshold or 80

        # Build jest.config.js sections
        sections = []

        # Header comment
        sections.append("// jest.config.js - Jest configuration with test classification patterns")
        sections.append("// Generated by Trustable AI framework (trustable-ai init)")
        sections.append("// See: docs/architecture/decisions/ADR-004-test-marker-taxonomy.md")
        sections.append("")

        # Start module.exports
        sections.append("module.exports = {")

        # Test discovery
        sections.append("  // Test Discovery")
        sections.append("  testMatch: [")
        for pattern in test_match:
            sections.append(f'    "{pattern}",')
        # Remove trailing comma from last item
        if test_match:
            sections[-1] = sections[-1].rstrip(',')
        sections.append("  ],")
        sections.append("")

        # Classification approach explanation
        sections.append("  // Test Classification Approaches")
        sections.append("  // Jest doesn't have native markers like pytest. Use one of these approaches:")
        sections.append("  //")
        sections.append("  // 1. Test name patterns:")
        sections.append("  //    describe('[unit][functional] User authentication', () => {")
        sections.append("  //      test('should validate credentials', () => { ... });")
        sections.append("  //    });")
        sections.append("  //")
        sections.append("  // 2. Comment annotations:")
        sections.append("  //    // @test-level: unit")
        sections.append("  //    // @test-type: functional")
        sections.append("  //    describe('User authentication', () => {")
        sections.append("  //      test('should validate credentials', () => { ... });")
        sections.append("  //    });")
        sections.append("  //")
        sections.append("  // 3. Test file organization:")
        sections.append("  //    tests/unit/functional/user.test.js")
        sections.append("  //    tests/integration/security/auth.test.js")
        sections.append("")

        # Test levels
        sections.append("  // Test Levels (exactly one required):")
        for level in get_test_levels():
            description = get_test_level_description(level)
            sections.append(f"  // [{level}] - {description}")
        sections.append("")

        # Test types
        sections.append("  // Test Types (at least one required):")
        for test_type in get_test_types():
            description = get_test_type_description(test_type)
            sections.append(f"  // [{test_type}] - {description}")
        sections.append("")

        # Modifiers
        sections.append("  // Modifiers (optional):")
        for modifier in get_modifiers():
            description = get_modifier_description(modifier)
            sections.append(f"  // [{modifier}] - {description}")
        sections.append("")

        # Example usage
        sections.append("  // Example Test Classification:")
        sections.append("  // describe('[unit][functional] Calculator', () => {")
        sections.append("  //   test('should add two numbers', () => {")
        sections.append("  //     expect(add(2, 3)).toBe(5);")
        sections.append("  //   });")
        sections.append("  // });")
        sections.append("  //")
        sections.append("  // describe('[integration][security][requires-db] User service', () => {")
        sections.append("  //   test('should authenticate user with valid credentials', async () => {")
        sections.append("  //     const user = await authenticateUser('test@example.com', 'password');")
        sections.append("  //     expect(user).toBeDefined();")
        sections.append("  //   });")
        sections.append("  // });")
        sections.append("")

        # Coverage configuration
        sections.append("  // Coverage Configuration")
        sections.append("  collectCoverageFrom: [")
        sections.append('    "src/**/*.{js,jsx,ts,tsx}",')
        sections.append('    "!src/**/*.d.ts",')
        sections.append('    "!src/**/*.stories.{js,jsx,ts,tsx}",')
        sections.append('    "!src/**/__tests__/**"')
        sections.append("  ],")
        sections.append("")
        sections.append("  coverageThreshold: {")
        sections.append("    global: {")
        sections.append(f"      branches: {coverage_threshold},")
        sections.append(f"      functions: {coverage_threshold},")
        sections.append(f"      lines: {coverage_threshold},")
        sections.append(f"      statements: {coverage_threshold}")
        sections.append("    }")
        sections.append("  },")
        sections.append("")

        # Environment
        sections.append("  // Test Environment")
        sections.append('  testEnvironment: "node",')
        sections.append("")

        # Verbose output
        sections.append("  // Output Settings")
        sections.append("  verbose: true,")
        sections.append("")

        # TypeScript support hint
        sections.append("  // TypeScript Support (uncomment if using TypeScript)")
        sections.append("  // preset: 'ts-jest',")
        sections.append("  // transform: {")
        sections.append("  //   '^.+\\\\.tsx?$': 'ts-jest',")
        sections.append("  // },")
        sections.append("")

        # Additional helpful comments
        sections.append("  // Running specific test types:")
        sections.append("  // npm test -- --testNamePattern='\\[unit\\]'           # Run only unit tests")
        sections.append("  // npm test -- --testNamePattern='\\[integration\\]'    # Run only integration tests")
        sections.append("  // npm test -- --testNamePattern='\\[functional\\]'     # Run only functional tests")
        sections.append("  // npm test -- --testNamePattern='\\[security\\]'       # Run only security tests")
        sections.append("  // npm test -- --testNamePattern='\\[slow\\]'           # Run only slow tests")

        # Close module.exports
        sections.append("};")
        sections.append("")

        return "\n".join(sections)

    def write_to_file(self, content: str, output_path: Path) -> None:
        """
        Write jest.config.js content to file.

        Args:
            content: jest.config.js file content from generate_jest_config()
            output_path: Path to write jest.config.js file

        Raises:
            OSError: If file cannot be written
            ValueError: If content is empty

        Example:
            >>> generator = JestConfigGenerator()
            >>> content = generator.generate_jest_config(Path("/my/project"))
            >>> generator.write_to_file(content, Path("/my/project/jest.config.js"))
        """
        if not content or not content.strip():
            raise ValueError("Cannot write empty jest.config.js content")

        # Create parent directory if needed
        output_path.parent.mkdir(parents=True, exist_ok=True)

        # Write file
        output_path.write_text(content, encoding="utf-8")

    def validate_jest_config(self, content: str) -> bool:
        """
        Validate jest.config.js content structure.

        Checks that generated content has:
        1. module.exports declaration
        2. At least one testMatch pattern
        3. Test classification comments explaining approaches
        4. Coverage configuration

        Args:
            content: jest.config.js file content to validate

        Returns:
            True if valid, False otherwise

        Example:
            >>> generator = JestConfigGenerator()
            >>> content = generator.generate_jest_config(Path("/my/project"))
            >>> assert generator.validate_jest_config(content)
        """
        if not content or not content.strip():
            return False

        # Check for module.exports
        if "module.exports" not in content:
            return False

        # Check for testMatch configuration
        if "testMatch:" not in content and "testMatch :" not in content:
            return False

        # Check for classification comments
        if "Test Classification" not in content:
            return False

        # Check for coverage configuration
        if "coverageThreshold" not in content:
            return False

        # Check for test environment
        if "testEnvironment" not in content:
            return False

        return True
