"""Go build utilities."""

import shutil
import subprocess
from pathlib import Path
from typing import Final

from loguru import logger

from multi_lang_build.compiler.base import BuildResult


class GoBuilder:
    """Build Go binaries with various options."""

    DEFAULT_TARGETS: Final[list[str]] = ["linux/amd64", "linux/arm64", "darwin/amd64", "darwin/arm64"]

    @staticmethod
    def build(
        go_executable: str,
        source_dir: Path,
        output_path: Path,
        *,
        ldflags: str | None = None,
        tags: list[str] | None = None,
        environment: dict[str, str],
        stream_output: bool = True,
    ) -> BuildResult:
        """Build a Go binary.

        Args:
            go_executable: Path to Go executable
            source_dir: Source directory
            output_path: Output path for binary
            ldflags: Linker flags
            tags: Build tags
            environment: Environment variables
            stream_output: Whether to stream output

        Returns:
            BuildResult with success status
        """
        build_args = [go_executable, "build", "-o", str(output_path)]

        if ldflags:
            build_args.extend(["-ldflags", ldflags])

        if tags:
            build_args.extend(["-tags", ",".join(tags)])

        return GoBuilder._run_build(
            build_args, source_dir, environment, stream_output
        )

    @staticmethod
    def build_all(
        go_executable: str,
        source_dir: Path,
        output_dir: Path,
        *,
        environment: dict[str, str],
        stream_output: bool = True,
    ) -> BuildResult:
        """Build all packages in the module.

        Args:
            go_executable: Path to Go executable
            source_dir: Source directory
            output_dir: Output directory for binaries
            environment: Environment variables
            stream_output: Whether to stream output

        Returns:
            BuildResult with success status
        """
        build_args = [go_executable, "build", "-o", str(output_dir), "./..."]

        return GoBuilder._run_build(
            build_args, source_dir, environment, stream_output
        )

    @staticmethod
    def cross_compile(
        go_executable: str,
        source_dir: Path,
        output_path: Path,
        target: str,
        *,
        ldflags: str | None = None,
        environment: dict[str, str],
        stream_output: bool = True,
    ) -> BuildResult:
        """Cross-compile for a specific platform.

        Args:
            go_executable: Path to Go executable
            source_dir: Source directory
            output_path: Output path for binary
            target: Target platform (e.g., "linux/amd64")
            ldflags: Linker flags
            environment: Environment variables
            stream_output: Whether to stream output

        Returns:
            BuildResult with success status
        """
        build_args = [
            go_executable, "build",
            "-o", str(output_path),
            "-ldflags", f"{ldflags or ''} -s -w",
            "-GOOS", target.split("/")[0],
            "-GOARCH", target.split("/")[1],
        ]

        return GoBuilder._run_build(
            build_args, source_dir, environment, stream_output
        )

    @staticmethod
    def _run_build(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        stream_output: bool,
    ) -> BuildResult:
        """Execute build command."""
        import time

        start_time = time.perf_counter()

        try:
            if stream_output:
                return GoBuilder._stream_build(
                    command, source_dir, environment, start_time
                )
            else:
                return GoBuilder._capture_build(
                    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"Build error: {str(e)}",
                output_path=None,
                duration_seconds=duration,
            )

    @staticmethod
    def _stream_build(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        start_time: float,
    ) -> BuildResult:
        """Execute build 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 if return_code == 0 else None,
            duration_seconds=duration,
        )

    @staticmethod
    def _capture_build(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        start_time: float,
    ) -> BuildResult:
        """Execute build 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 if result.returncode == 0 else None,
            duration_seconds=duration,
        )
