"""
shamash-openclaw-setup — One-command setup for the Shamash OpenClaw plugin.

Steps:
  1. Verify ~/.openclaw/ exists (OpenClaw installed)
  2. Copy plugin files to ~/.openclaw/plugins/shamash-openclaw/
  3. Download the platform-appropriate shamash binary from GitHub Releases
  4. Register the plugin path in ~/.openclaw/openclaw.json (idempotent)
"""

from __future__ import annotations

import json
import hashlib
import os
import platform
import shutil
import stat
import sys
import urllib.request
from pathlib import Path

PLUGIN_NAME = "shamash-openclaw"

# Binary release tag — pinned independently of the JS plugin version.
# The shamash binary is compiled from the Rust SDK and only changes on SDK releases.
BINARY_RELEASE_TAG = "v0.2.0"


def _release_base() -> str:
    """Return the GitHub Releases base URL for the pinned binary version."""
    return f"https://github.com/uruk-space/shamash/releases/download/{BINARY_RELEASE_TAG}"


# Files to copy from the bundled plugin/ directory into the install target
PLUGIN_FILES = [
    "dist/index.js",
    "dist/index.d.ts",
    "dist/scanner.js",
    "dist/scanner.d.ts",
    "dist/telemetry.js",
    "dist/telemetry.d.ts",
    "openclaw.plugin.json",
    "package.json",
]


def _openclaw_dir() -> Path:
    return Path.home() / ".openclaw"


def _plugin_source_dir() -> Path:
    """Return the path to the bundled plugin files shipped with this package."""
    return Path(__file__).parent / "plugin"


def _resolve_binary_name() -> str | None:
    """Map current platform/arch to the Shamash release binary name."""
    system = platform.system().lower()
    machine = platform.machine().lower()

    platform_map = {"darwin": "darwin", "linux": "linux", "windows": "windows"}
    arch_map = {"x86_64": "x64", "amd64": "x64", "aarch64": "arm64", "arm64": "arm64"}

    mapped_platform = platform_map.get(system)
    mapped_arch = arch_map.get(machine)

    if not mapped_platform or not mapped_arch:
        return None

    ext = ".exe" if system == "windows" else ""
    return f"shamash-{mapped_platform}-{mapped_arch}{ext}"


def _download(url: str, dest: Path) -> None:
    """Download a file from url to dest, following redirects."""
    req = urllib.request.Request(url, headers={"User-Agent": "shamash-openclaw-setup"})
    with urllib.request.urlopen(req, timeout=120) as resp:
        with open(dest, "wb") as f:
            shutil.copyfileobj(resp, f)


def _download_text(url: str) -> str:
    """Download UTF-8 text payload from url, following redirects."""
    req = urllib.request.Request(url, headers={"User-Agent": "shamash-openclaw-setup"})
    with urllib.request.urlopen(req, timeout=120) as resp:
        return resp.read().decode("utf-8")


def _parse_sha256sums(checksum_text: str) -> dict[str, str]:
    checksums: dict[str, str] = {}
    for line in checksum_text.splitlines():
        line = line.strip()
        if not line:
            continue
        parts = line.split()
        if len(parts) < 2:
            continue
        digest = parts[0].lower()
        filename = parts[-1].lstrip("*")
        if len(digest) == 64:
            checksums[filename] = digest
    return checksums


def _sha256_file(file_path: Path) -> str:
    digest = hashlib.sha256()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            digest.update(chunk)
    return digest.hexdigest()


def _verify_binary_checksum(binary_name: str, binary_path: Path, checksum_text: str) -> None:
    checksums = _parse_sha256sums(checksum_text)
    expected = checksums.get(binary_name)
    if not expected:
        raise RuntimeError(f"Missing checksum entry for {binary_name}")
    actual = _sha256_file(binary_path)
    if actual != expected:
        raise RuntimeError(
            f"Checksum mismatch for {binary_name}: expected {expected}, got {actual}"
        )


def _copy_plugin_files(target_dir: Path) -> None:
    """Copy bundled plugin files to the target directory."""
    source_dir = _plugin_source_dir()

    for rel_path in PLUGIN_FILES:
        src = source_dir / rel_path
        dst = target_dir / rel_path

        if not src.exists():
            print(f"  WARNING: Missing bundled file: {rel_path}")
            continue

        dst.parent.mkdir(parents=True, exist_ok=True)
        # If src and dst resolve to the same inode (hardlink/symlink from
        # a prior editable install), read content first, break the link,
        # then write a fresh independent copy.
        try:
            same = dst.exists() and os.path.samefile(src, dst)
        except OSError:
            same = False
        if same:
            data = src.read_bytes()
            dst.unlink()
            dst.write_bytes(data)
        else:
            shutil.copy2(src, dst)
        print(f"  Copied {rel_path}")


def _download_binary(target_dir: Path) -> None:
    """Download the platform-appropriate shamash binary into target_dir/bin/."""
    binary_name = _resolve_binary_name()
    if not binary_name:
        print(
            f"  WARNING: Unsupported platform: {platform.system()}/{platform.machine()}"
        )
        print("  You can manually install shamash and set binaryPath in your OpenClaw config.")
        return

    bin_dir = target_dir / "bin"
    bin_dir.mkdir(parents=True, exist_ok=True)

    local_name = "shamash.exe" if platform.system().lower() == "windows" else "shamash"
    dest = bin_dir / local_name
    release_base = _release_base()
    url = f"{release_base}/{binary_name}"
    checksum_url = f"{release_base}/SHA256SUMS.txt"

    # Skip download if binary already exists and checksum validates
    if dest.exists():
        print("  Binary already exists, verifying checksum...")
        try:
            checksum_text = _download_text(checksum_url)
            _verify_binary_checksum(binary_name, dest, checksum_text)
            print(f"  Existing binary verified: {dest}")
            return
        except Exception:
            print("  Existing binary failed checksum, re-downloading...")

    print("  Fetching SHA256SUMS.txt...")
    print(f"  Downloading {binary_name}...")
    try:
        checksum_text = _download_text(checksum_url)
        _download(url, dest)
        _verify_binary_checksum(binary_name, dest, checksum_text)
        if platform.system().lower() != "windows":
            dest.chmod(dest.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
        print(f"  Binary saved to {dest}")
    except Exception as e:
        if dest.exists():
            dest.unlink()
        raise RuntimeError(f"Fail-closed binary install: {e}") from e


def _register_plugin_path(plugin_dir: Path) -> None:
    """Register the plugin path in ~/.openclaw/openclaw.json (idempotent)."""
    config_path = _openclaw_dir() / "openclaw.json"

    config: dict = {}
    if config_path.exists():
        config = json.loads(config_path.read_text(encoding="utf-8"))

    # Ensure plugins.load.paths exists
    plugins = config.setdefault("plugins", {})
    load = plugins.setdefault("load", {})
    paths: list = load.setdefault("paths", [])

    plugin_path_str = str(plugin_dir)
    if plugin_path_str not in paths:
        paths.append(plugin_path_str)
        config_path.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
        print(f"  Registered plugin path in {config_path}")
    else:
        print(f"  Plugin path already registered in {config_path}")


def main() -> None:
    print(f"[{PLUGIN_NAME}] Setting up Shamash OpenClaw plugin...")

    openclaw_dir = _openclaw_dir()
    if not openclaw_dir.exists():
        print(f"  ERROR: {openclaw_dir} not found. Is OpenClaw installed?")
        print("  Install OpenClaw first, then re-run: shamash-openclaw-setup")
        sys.exit(1)

    plugin_dir = openclaw_dir / "plugins" / PLUGIN_NAME
    plugin_dir.mkdir(parents=True, exist_ok=True)

    print(f"  Installing to {plugin_dir}")

    # Step 1: Copy plugin files
    _copy_plugin_files(plugin_dir)

    # Step 2: Download shamash binary
    try:
        _download_binary(plugin_dir)
    except RuntimeError as e:
        print(f"  ERROR: {e}")
        print("  Binary install aborted to avoid unverified executable.")
        sys.exit(1)

    # Step 3: Register in openclaw.json
    _register_plugin_path(plugin_dir)

    print(f"[{PLUGIN_NAME}] Setup complete. Restart OpenClaw to activate the 4-gate firewall.")


if __name__ == "__main__":
    main()
