import subprocess
import sys
from .environment import check_python_compatibility, check_platform_compatibility
from .resolver import resolve_conflicts
from .build import check_and_fix_build_deps
from .diagnostics import verify_install


def install(package: str, version: str = None, verbose: bool = False) -> dict:
    """
    Full peep install pipeline for a single package.
    Runs all checks, auto-fixes what it can, then delegates to pip.
    Returns a full report of what happened.
    """
    report = {
        "package": package,
        "version": version,
        "steps": {},
        "success": False,
        "final_version": None,
    }

    target = f"{package}=={version}" if version else package
    resolved_version = version  # May be updated by compatibility checks

    # ── Step 1: Python version compatibility ─────────────────────────────────
    py_check = check_python_compatibility(package, version)
    report["steps"]["python_compatibility"] = py_check

    if py_check.get("compatible") is False:
        suggested = py_check.get("suggested_version")
        if suggested:
            resolved_version = suggested
            target = f"{package}=={suggested}"
            report["steps"]["python_compatibility"]["action"] = f"Switched to {package}=={suggested}"
        else:
            report["error"] = f"{package} has no version compatible with Python {py_check['current_python']}"
            return report

    # ── Step 2: Platform compatibility ───────────────────────────────────────
    plat_check = check_platform_compatibility(package, resolved_version)
    report["steps"]["platform_compatibility"] = plat_check

    needs_compilation = plat_check.get("needs_compilation", False)

    if not plat_check.get("has_compatible_wheel") and not plat_check.get("has_sdist"):
        report["error"] = f"No compatible distribution found for {package} on {plat_check.get('platform')}/{plat_check.get('machine')}"
        return report

    # ── Step 3: Dependency conflict resolution ────────────────────────────────
    conflict_check = resolve_conflicts(package, resolved_version)
    report["steps"]["dependency_resolution"] = conflict_check

    if not conflict_check["clean"]:
        report["error"] = f"Unresolvable dependency conflicts for {package}: {conflict_check['conflicts']}"
        return report

    # Silently pre-install or upgrade conflicting deps before the main package
    for dep in conflict_check["to_install"] + conflict_check["to_upgrade"]:
        dep_target = f"{dep['package']}=={dep.get('version') or dep.get('to')}" if dep.get("version") or dep.get("to") else dep["package"]
        _run_pip(["install", dep_target], verbose=verbose)

    # ── Step 4: Build dependency check + fix ─────────────────────────────────
    build_check = check_and_fix_build_deps(package, needs_compilation)
    report["steps"]["build_deps"] = build_check

    if build_check.get("failed"):
        hints = [f["hint"] for f in build_check["failed"] if f.get("hint")]
        report["error"] = (
            f"Could not auto-install build dependencies: "
            f"{[f['dep'] for f in build_check['failed']]}. "
            f"Manual steps: {hints}"
        )
        return report

    # ── Step 5: Run pip ───────────────────────────────────────────────────────
    pip_result = _run_pip(["install", target], verbose=verbose)
    report["steps"]["pip"] = pip_result

    if pip_result["returncode"] != 0:
        # One retry: let pip attempt its own conflict resolution
        retry_result = _run_pip(["install", target, "--upgrade"], verbose=verbose)
        report["steps"]["pip_retry"] = retry_result

        if retry_result["returncode"] != 0:
            report["error"] = f"pip failed:\n{retry_result['stderr']}"
            return report

    # ── Step 6: Post-install verification ─────────────────────────────────────
    verify = verify_install(package)
    report["steps"]["verification"] = verify

    if not verify["importable"]:
        report["error"] = f"Package installed but failed to import: {verify.get('error')}"
        return report

    report["success"] = True
    report["final_version"] = verify.get("version") or resolved_version
    return report


def install_many(packages: list[str], verbose: bool = False) -> list[dict]:
    """Install multiple packages, collecting a report for each."""
    return [install(pkg, verbose=verbose) for pkg in packages]


def _run_pip(args: list[str], verbose: bool = False) -> dict:
    """Shell out to pip with the given args. Returns returncode, stdout, stderr."""
    cmd = [sys.executable, "-m", "pip"] + args

    if not verbose:
        args_with_quiet = cmd + ["-q"]
    else:
        args_with_quiet = cmd

    result = subprocess.run(args_with_quiet, capture_output=True, text=True)

    return {
        "command": " ".join(args_with_quiet),
        "returncode": result.returncode,
        "stdout": result.stdout.strip(),
        "stderr": result.stderr.strip(),
    }