"""Go test utilities."""

import os
import subprocess
import sys
import time
from pathlib import Path
from typing import Callable

from loguru import logger

from multi_lang_build.compiler.base import BuildResult


class GoTester:
    """Run Go tests."""

    @staticmethod
    def run(
        go_executable: str,
        source_dir: Path,
        env: dict[str, str],
        verbose: bool = True,
        race: bool = False,
        stream_output: bool = True,
        run_build: Callable | None = None,
    ) -> BuildResult:
        """Run Go tests.

        Args:
            go_executable: Path to Go executable
            source_dir: Source directory
            env: Environment variables
            verbose: Enable verbose test output
            race: Enable race detector
            stream_output: Whether to stream output
            run_build: Optional custom build runner

        Returns:
            BuildResult with success status
        """
        test_args = [go_executable, "test"]

        if verbose:
            test_args.append("-v")
        if race:
            test_args.append("-race")

        test_args.append("./...")

        logger.info("🧪 开始运行测试...")
        logger.info(f"构建命令: {' '.join(test_args)}")

        if run_build:
            result = run_build(test_args, source_dir, source_dir, env)
        else:
            result = GoTester._run_test(test_args, source_dir, env, stream_output)

        if result["success"]:
            logger.info("✅ 测试完成")

        return result

    @staticmethod
    def run_with_coverage(
        go_executable: str,
        source_dir: Path,
        output_file: Path,
        env: dict[str, str],
        stream_output: bool = True,
    ) -> BuildResult:
        """Run tests with coverage.

        Args:
            go_executable: Path to Go executable
            source_dir: Source directory
            output_file: Output file for coverage report
            env: Environment variables
            stream_output: Whether to stream output

        Returns:
            BuildResult with success status
        """
        test_args = [
            go_executable, "test",
            "-v",
            "-coverprofile", str(output_file),
            "./...",
        ]

        return GoTester._run_test(test_args, source_dir, env, stream_output)

    @staticmethod
    def _run_test(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        stream_output: bool,
    ) -> BuildResult:
        """Execute test command."""
        start_time = time.perf_counter()

        try:
            if stream_output:
                return GoTester._stream_test(
                    command, source_dir, environment, start_time
                )
            else:
                return GoTester._capture_test(
                    command, source_dir, environment, start_time
                )
        except Exception as e:
            duration = time.perf_counter() - start_time
            return BuildResult(
                success=False,
                return_code=-2,
                stdout="",
                stderr=f"Test error: {str(e)}",
                output_path=None,
                duration_seconds=duration,
            )

    @staticmethod
    def _stream_test(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        start_time: float,
    ) -> BuildResult:
        """Execute tests with streaming output."""
        import os
        import sys

        stdout_buffer = []
        stderr_buffer = []

        process = subprocess.Popen(
            command,
            cwd=source_dir,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            env={**os.environ, **environment},
        )

        # Read stdout
        if process.stdout:
            for line in process.stdout:
                line = line.rstrip('\n\r')
                stdout_buffer.append(line)
                print(line)
                sys.stdout.flush()

        # Read stderr
        if process.stderr:
            for line in process.stderr:
                line = line.rstrip('\n\r')
                stderr_buffer.append(line)
                print(line, file=sys.stderr)
                sys.stderr.flush()

        return_code = process.wait()
        duration = time.perf_counter() - start_time

        return BuildResult(
            success=return_code == 0,
            return_code=return_code,
            stdout='\n'.join(stdout_buffer),
            stderr='\n'.join(stderr_buffer),
            output_path=source_dir,
            duration_seconds=duration,
        )

    @staticmethod
    def _capture_test(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        start_time: float,
    ) -> BuildResult:
        """Execute tests with captured output."""
        result = subprocess.run(
            command,
            cwd=source_dir,
            capture_output=True,
            text=True,
            timeout=3600,
            env={**os.environ, **environment},
        )

        duration = time.perf_counter() - start_time

        return BuildResult(
            success=result.returncode == 0,
            return_code=result.returncode,
            stdout=result.stdout,
            stderr=result.stderr,
            output_path=source_dir,
            duration_seconds=duration,
        )
