"""Subprocess execution with environment variable injection."""

from __future__ import annotations

import os
import signal
import subprocess
import sys
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from tacoshop.cli import ParseResult
    from tacoshop.config import Config, FlagVar, StaticVar


def _apply_var(
    env: dict[str, str],
    name: str,
    value: str,
    append: bool,
    prepend: bool,
    separator: str,
) -> None:
    """Set, append, or prepend an env var in the env dict."""
    if not append and not prepend:
        env[name] = value
        return

    existing = env.get(name)
    if existing is None:
        env[name] = value
    elif append:
        if separator and existing.endswith(separator):
            env[name] = existing + value
        elif separator:
            env[name] = existing + separator + value
        else:
            env[name] = existing + value
    else:  # prepend
        if separator and existing.startswith(separator):
            env[name] = value + existing
        elif separator:
            env[name] = value + separator + existing
        else:
            env[name] = value + existing


def build_env(config: Config, result: ParseResult) -> dict[str, str]:
    """Build the environment dict from config and activated flags."""
    env = os.environ.copy()

    # Apply static vars
    for sv in config.static_vars.values():
        _apply_var(env, sv.name, sv.value, sv.append, sv.prepend, sv.separator)

    # Apply activated flag vars
    for env_name, value in result.activated_flags.items():
        fv: FlagVar = config.flag_vars[env_name]
        _apply_var(env, env_name, value, fv.append, fv.prepend, fv.separator)

    return env


def _format_env_changes(config: Config, result: ParseResult) -> list[str]:
    """Format the env var changes for verbose/dry-run output."""
    lines: list[str] = []
    for sv in config.static_vars.values():
        suffix = " (append)" if sv.append else " (prepend)" if sv.prepend else ""
        lines.append(f"  {sv.name}={sv.value}{suffix}")
    for env_name, value in result.activated_flags.items():
        fv = config.flag_vars[env_name]
        suffix = " (append)" if fv.append else " (prepend)" if fv.prepend else ""
        lines.append(f"  {env_name}={value}{suffix}")
    return lines


def run_command(command: list[str], config: Config, result: ParseResult) -> None:
    """Execute a command with configured environment variables."""
    env = build_env(config, result)
    env_lines = _format_env_changes(config, result)

    if result.dry_run:
        if env_lines:
            print("Environment variables:", file=sys.stderr)
            for line in env_lines:
                print(line, file=sys.stderr)
        print(f"Command: {command}", file=sys.stderr)
        sys.exit(0)

    if result.verbose and env_lines:
        print("tacoshop: setting environment variables:", file=sys.stderr)
        for line in env_lines:
            print(line, file=sys.stderr)

    try:
        proc = subprocess.run(command, env=env)
        sys.exit(proc.returncode)
    except KeyboardInterrupt:
        sys.exit(128 + signal.SIGINT)
    except FileNotFoundError:
        print(f"tacoshop: command not found: {command[0]}", file=sys.stderr)
        sys.exit(127)
