"""Test command implementations for MakePython."""

from __future__ import annotations

import webbrowser
from typing import TYPE_CHECKING
from urllib.request import pathname2url

from ...core.executor import execute_command_with_context
from ...interfaces.command import CommandResult, CommandType, ValidatableCommand

if TYPE_CHECKING:
    from ...core.context import ExecutionContext


class TestCommand(ValidatableCommand):
    """Run tests with parallel execution."""

    name = "test"
    alias = "t"
    description = "Run tests with parallel execution"
    command_type = CommandType.TEST

    def validate(self, context: ExecutionContext) -> bool:
        """Validate test command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pytest is available
        result = execute_command_with_context(["pytest", "--version"], context)
        if not result.success:
            self.logger.warning("pytest not found, but will attempt to run anyway")

        return True

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute test command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        self.logger.info("Running tests with parallel execution...")

        # Execute tests with real-time output
        from ...core.executor import CommandExecutor

        cmd = ["pytest", "-n", "8"]
        executor = CommandExecutor(context)
        result = executor.execute_shell_command(cmd)

        if result.success:
            self.logger.info("Tests completed successfully!")
        else:
            self.logger.error(f"Tests failed with exit code {result.exit_code}")

        return result


class TestDefaultCommand(ValidatableCommand):
    """Run tests with default execution."""

    name = "test-default"
    alias = "td"
    description = "Run tests with default execution"
    command_type = CommandType.TEST

    def validate(self, context: ExecutionContext) -> bool:
        """Validate test command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pytest is available
        result = execute_command_with_context(["pytest", "--version"], context)
        if not result.success:
            self.logger.warning("pytest not found, but will attempt to run anyway")

        return True

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute default test command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        self.logger.info("Running tests with default execution...")

        # Execute tests with real-time output
        from ...core.executor import CommandExecutor

        cmd = ["pytest"]
        executor = CommandExecutor(context)
        result = executor.execute_shell_command(cmd)

        if result.success:
            self.logger.info("Tests completed successfully!")
        else:
            self.logger.error(f"Tests failed with exit code {result.exit_code}")

        return result


class TestBenchmarkCommand(ValidatableCommand):
    """Run benchmark tests specifically."""

    name = "test-benchmark"
    alias = "tb"
    description = "Run benchmark tests specifically"
    command_type = CommandType.TEST

    def validate(self, context: ExecutionContext) -> bool:
        """Validate benchmark test command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pytest is available
        result = execute_command_with_context(["pytest", "--version"], context)
        if not result.success:
            self.logger.warning("pytest not found, but will attempt to run anyway")

        return True

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute benchmark test command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        self.logger.info("Running benchmark tests...")

        # Execute benchmark tests with real-time output
        from ...core.executor import CommandExecutor

        cmd = ["pytest", "-m", "benchmark", "-n", "8"]
        executor = CommandExecutor(context)
        result = executor.execute_shell_command(cmd)

        if result.success:
            self.logger.info("Benchmark tests completed successfully!")
        else:
            self.logger.error(f"Benchmark tests failed with exit code {result.exit_code}")

        return result


class TestCoverageCommand(ValidatableCommand):
    """Run tests with coverage reporting."""

    name = "test-coverage"
    alias = "tc"
    description = "Run tests with coverage reporting"
    command_type = CommandType.TEST

    def validate(self, context: ExecutionContext) -> bool:
        """Validate test coverage command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pytest and coverage are available
        pytest_result = execute_command_with_context(["pytest", "--version"], context)
        coverage_result = execute_command_with_context(["coverage", "--version"], context)

        if not pytest_result.success:
            self.logger.warning("pytest not found, but will attempt to run anyway")

        if not coverage_result.success:
            self.logger.warning("coverage not found, but will attempt to run anyway")

        return True

    def execute(self, context: ExecutionContext, slow_mode: bool = False) -> CommandResult:
        """Execute test coverage command.

        Args:
            context: Execution context
            slow_mode: Whether to run slow tests

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        try:
            # Run tests with coverage
            from ...core.executor import CommandExecutor

            pytest_cmd = ["pytest", "--cov"]
            if slow_mode:
                pytest_cmd.append("--runslow")

            executor = CommandExecutor(context)
            result = executor.execute_shell_command(pytest_cmd)
            if not result.success:
                return result

            # Generate coverage report
            coverage_result = executor.execute_shell_command(["coverage", "report", "-m"])
            if not coverage_result.success:
                self.logger.warning("Coverage report generation had issues")

            # Generate HTML report
            html_result = executor.execute_shell_command(["coverage", "html"])
            if not html_result.success:
                self.logger.warning("HTML coverage report generation had issues")

            # Try to open in browser
            html_report = context.cwd / "htmlcov" / "index.html"
            if html_report.exists():
                webbrowser.open("file://" + pathname2url(str(html_report)))
                self.logger.info("Coverage report opened in browser")
            else:
                self.logger.warning("HTML coverage report not found")

            return CommandResult(
                success=True,
                message="Coverage tests completed successfully!",
                data={
                    "coverage_report_success": coverage_result.success,
                    "html_report_success": html_result.success,
                },
            )

        except Exception as e:
            self.logger.error(f"Coverage report generation failed: {e}")
            return CommandResult(success=False, message=f"Coverage report generation failed: {e}")


class TestCoverageSlowCommand(ValidatableCommand):
    """Run tests with coverage reporting (slow mode)."""

    name = "test-coverage-slow"
    alias = "tcs"
    description = "Run tests with coverage reporting (slow mode)"
    command_type = CommandType.TEST

    def validate(self, context: ExecutionContext) -> bool:
        """Validate test coverage command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Reuse validation from TestCoverageCommand
        coverage_cmd = TestCoverageCommand()
        return coverage_cmd.validate(context)

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute slow coverage test command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        coverage_cmd = TestCoverageCommand()
        return coverage_cmd.execute(context, slow_mode=True)
