import json
import subprocess
from pathlib import Path
from typing import Any


def run_build(project_dir: Path) -> subprocess.CompletedProcess:
    return subprocess.run(
        ["bun", "run", "n6k-build"],
        capture_output=True,
        text=True,
        cwd=str(project_dir),
    )


def read_missing_json(build_dir: Path) -> set[str]:
    """Read missing.json and return all unique PascalCase component names."""
    missing_file = build_dir / "missing.json"
    if not missing_file.exists():
        return set()
    entries = json.loads(missing_file.read_text())
    names = set()
    for entry in entries:
        for comp in entry["components"]:
            names.add(comp)
    return names


def ensure_deps(project_dir: Path):
    """bun install if node_modules missing."""
    if not (project_dir / "node_modules").exists():
        result = subprocess.run(
            ["bun", "install", "--cwd", str(project_dir)],
            capture_output=True,
            text=True,
        )
        if result.returncode != 0:
            raise RuntimeError(f"Failed to install dependencies:\n{result.stderr}")


def write_config(
    project_dir: Path,
    *,
    bindings: dict[str, Any],
    app_dir: str | None = None,
    entry_points: dict[str, str] | None = None,
    config_fn=None,
):
    config: dict[str, Any] = {}
    if bindings:
        config["wrappers"] = [{
            "component": "BindingProvider",
            "import": "import { BindingProvider } from '@n6k.io/ui/lib/binding-provider';",
            "props": {"defaults": bindings},
        }]
    if app_dir:
        config["appDir"] = app_dir
    if entry_points:
        config["entryPoints"] = entry_points
    if config_fn:
        config_fn(project_dir, config)
    build_dir = project_dir / "build"
    build_dir.mkdir(parents=True, exist_ok=True)
    (build_dir / "n6k.config.json").write_text(json.dumps(config, indent=2) + "\n")


def build_css(project_dir: Path):
    """Build Tailwind CSS to project_dir/build/styles.css."""
    build_dir = project_dir / "build"
    build_dir.mkdir(parents=True, exist_ok=True)

    result = subprocess.run(
        [
            "bunx",
            "@tailwindcss/cli",
            "-i", "src/app/globals.css",
            "-o", str((build_dir / "styles.css").relative_to(project_dir)),
        ],
        capture_output=True,
        text=True,
        cwd=str(project_dir),
    )

    if result.returncode != 0:
        raise RuntimeError(f"Tailwind CSS build failed:\n{result.stderr}")


