"""Python dependency installation."""

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

from multi_lang_build.compiler.base import BuildResult


class DependencyInstaller:
    """Install Python dependencies for various build systems."""

    @staticmethod
    def install_poetry(
        python_executable: str,
        source_dir: Path,
        environment: dict[str, str],
        dev: bool = False,
        stream_output: bool = True,
    ) -> BuildResult:
        """Install dependencies using Poetry."""
        cmd = [python_executable, "-m", "poetry", "install"]
        if dev:
            cmd.append("--with=dev")

        return DependencyInstaller._run_pip(
            cmd, source_dir, source_dir, environment, stream_output
        )

    @staticmethod
    def install_pip(
        python_executable: str,
        source_dir: Path,
        environment: dict[str, str],
        dev: bool = False,
        stream_output: bool = True,
    ) -> BuildResult:
        """Install dependencies using pip."""
        cmd = [python_executable, "-m", "pip", "install", "-r", str(source_dir / "requirements.txt")]

        if dev:
            cmd.append("-r")
            cmd.append(str(source_dir / "requirements-dev.txt"))

        return DependencyInstaller._run_pip(
            cmd, source_dir, source_dir, environment, stream_output
        )

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

        start_time = time.perf_counter()

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

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

        stdout_buffer = []
        stderr_buffer = []

        process = sp.Popen(
            command,
            cwd=source_dir,
            stdout=sp.PIPE,
            stderr=sp.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_pip(
        command: list[str],
        source_dir: Path,
        environment: dict[str, str],
        start_time: float,
    ) -> BuildResult:
        """Execute pip 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,
        )
