#!/usr/bin/env python3
"""Create a share-safer development toolchain fingerprint.

The script runs locally, invokes only version commands, and does not inspect a
project, environment-variable values, Git remotes, credentials, or user files.
"""
from __future__ import annotations

import argparse
import os
import platform
import shutil
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class Tool:
    name: str
    commands: tuple[tuple[str, ...], ...]


TOOLS = (
    Tool("Python", ((sys.executable, "--version"),)),
    Tool("pip", ((sys.executable, "-m", "pip", "--version"),)),
    Tool("Java", (("java", "-version"),)),
    Tool("javac", (("javac", "-version"),)),
    Tool("Git", (("git", "--version"),)),
    Tool("Node.js", (("node", "--version"),)),
    Tool("npm", (("npm", "--version"),)),
    Tool("CMake", (("cmake", "--version"),)),
    Tool("Gradle", (("gradle", "--version"),)),
    Tool("Maven", (("mvn", "-version"),)),
)


def redact_home(value: str | None, home: Path | None = None) -> str:
    """Replace the current home path in a value without resolving user files."""
    if not value:
        return ""
    home_text = str(home or Path.home())
    variants = {home_text, home_text.replace(os.sep, "/"), home_text.replace(os.sep, "\\")}
    redacted = value
    for variant in sorted(variants, key=len, reverse=True):
        if variant:
            redacted = redacted.replace(variant, "<HOME>")
    return redacted


def executable_for(command: tuple[str, ...]) -> str | None:
    if command[0] == sys.executable:
        return sys.executable
    return shutil.which(command[0])


def version_line(command: tuple[str, ...], timeout: float = 5.0) -> dict[str, object]:
    executable = executable_for(command)
    if not executable:
        return {"found": False, "executable": "", "version": "not found", "exit_code": None}
    try:
        completed = subprocess.run(
            [executable, *command[1:]],
            capture_output=True,
            text=True,
            timeout=timeout,
            shell=False,
            check=False,
        )
        lines = (completed.stdout + "\n" + completed.stderr).strip().splitlines()
        first = next((line.strip() for line in lines if line.strip()), "unknown")
        return {
            "found": True,
            "executable": redact_home(executable),
            "version": redact_home(first),
            "exit_code": completed.returncode,
        }
    except (OSError, subprocess.TimeoutExpired) as exc:
        return {
            "found": True,
            "executable": redact_home(executable),
            "version": f"check failed: {type(exc).__name__}",
            "exit_code": None,
        }


def collect() -> dict[str, object]:
    results = {tool.name: version_line(tool.commands[0]) for tool in TOOLS}
    python_prefix = redact_home(sys.prefix)
    base_prefix = redact_home(getattr(sys, "base_prefix", sys.prefix))
    warnings: list[str] = []
    if sys.prefix == getattr(sys, "base_prefix", sys.prefix):
        warnings.append("Python is not currently running inside a virtual environment.")
    if results["Java"]["found"] and not results["javac"]["found"]:
        warnings.append("Java is available but javac is missing; a full JDK may be required.")
    return {
        "system": {
            "os": platform.system(),
            "release": platform.release(),
            "architecture": platform.machine(),
        },
        "python": {
            "version": platform.python_version(),
            "executable": redact_home(sys.executable),
            "prefix": python_prefix,
            "base_prefix": base_prefix,
            "in_virtual_environment": sys.prefix != getattr(sys, "base_prefix", sys.prefix),
        },
        "tools": results,
        "warnings": warnings,
    }


def markdown(report: dict[str, object]) -> str:
    system = report["system"]
    python = report["python"]
    rows = []
    for name, result in report["tools"].items():
        status = "yes" if result["found"] else "no"
        rows.append(
            f"| {name} | {status} | `{result['version']}` | `{result['executable'] or '-'}` |"
        )
    warnings = report["warnings"]
    warning_text = "\n".join(f"- {warning}" for warning in warnings) if warnings else "- No basic mismatch detected."
    return f"""# Development environment fingerprint

Generated locally. Review this file before sharing it.

## Privacy boundary

- Home-directory paths are replaced with `<HOME>`.
- The tool does **not** read environment-variable values, Git remotes, credentials, project files, or user documents.
- The tool only invokes common `--version`/`-version` commands without a shell.

## System

- OS: `{system['os']}`
- Release: `{system['release']}`
- Architecture: `{system['architecture']}`
- Python: `{python['version']}`
- Python executable: `{python['executable']}`
- In virtual environment: `{str(python['in_virtual_environment']).lower()}`
- Python prefix: `{python['prefix']}`
- Python base prefix: `{python['base_prefix']}`

## Toolchain

| Tool | Found | Version | Executable |
|---|---:|---|---|
{chr(10).join(rows)}

## Basic warnings

{warning_text}

## Next comparison

Run the same command in the external terminal and in the IDE terminal. Compare Python executable, JDK/Gradle JVM, working directory, and tool versions before reinstalling dependencies.
"""


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Generate a local, share-safer development environment fingerprint."
    )
    parser.add_argument("--output", default="environment-fingerprint.md", help="Markdown output path")
    args = parser.parse_args()
    output = Path(args.output)
    output.write_text(markdown(collect()), encoding="utf-8")
    print(f"wrote {output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
