"""Plugin lifecycle: ensure, list, install, uninstall built-in plugins."""

import os
import shutil
import sys
from pathlib import Path
from typing import List, Optional, Tuple

from .paths import PLUGIN_DIR, PLUGIN_PATTERN, plugin_name

# Map of built-in plugin name -> (source module filename, install filename)
_BUILTINS = {
    "metadata": ("metadata.py", "00-metadata.py"),
    "chatmap": ("chatmap.py", "10-chatmap.py"),
}


def _builtin_source(module_filename: str) -> Path:
    """Return the path to a built-in plugin source file inside the package."""
    return Path(__file__).parent / "plugins" / module_filename


def ensure_plugin(name: str) -> Path:
    """Ensure a built-in plugin is installed in PLUGIN_DIR.

    If no file matching *-<name>.* exists, copies the package's built-in
    plugin with the canonical install filename. Idempotent.

    Returns the installed path.
    """
    if name not in _BUILTINS:
        raise ValueError(f"Unknown built-in plugin: {name!r}")

    PLUGIN_DIR.mkdir(parents=True, exist_ok=True)

    # Check if any file matching *-<name>.* already exists
    for p in PLUGIN_DIR.iterdir():
        if p.is_file() and plugin_name(p) == name:
            return p

    # Install from package
    src_filename, dest_filename = _BUILTINS[name]
    src = _builtin_source(src_filename)
    dest = PLUGIN_DIR / dest_filename
    shutil.copy2(src, dest)
    dest.chmod(0o755)
    return dest


def list_plugins() -> List[Tuple[Path, str, bool]]:
    """List installed plugins as (path, name, enabled) tuples."""
    if not PLUGIN_DIR.is_dir():
        return []

    result = []
    for p in sorted(PLUGIN_DIR.iterdir()):
        if not p.is_file():
            continue
        name = plugin_name(p)
        enabled = os.access(p, os.X_OK)
        result.append((p, name, enabled))
    return result


def install(src: Path, dest_name: Optional[str] = None) -> Path:
    """Copy a plugin file into PLUGIN_DIR.

    dest_name must match the NN-name.ext pattern. If not given, uses
    the source filename.
    """
    if not src.is_file():
        raise FileNotFoundError(f"{src} not found")

    if dest_name is None:
        dest_name = src.name

    if "." not in dest_name:
        dest_name += src.suffix

    if not PLUGIN_PATTERN.match(dest_name):
        raise ValueError(
            f"Filename must match NN-name.ext pattern (got {dest_name!r})"
        )

    PLUGIN_DIR.mkdir(parents=True, exist_ok=True)
    dest = PLUGIN_DIR / dest_name
    shutil.copy2(src, dest)
    dest.chmod(0o755)
    return dest


def uninstall(name: str) -> Optional[Path]:
    """Remove a plugin from PLUGIN_DIR by name match. Returns removed path or None."""
    if not PLUGIN_DIR.is_dir():
        return None

    for p in PLUGIN_DIR.iterdir():
        if plugin_name(p) == name:
            p.unlink()
            return p

    return None


def install_builtins() -> List[Path]:
    """Install or update all built-in plugins. Returns list of installed paths."""
    installed = []
    for name in _BUILTINS:
        src_filename, dest_filename = _BUILTINS[name]
        src = _builtin_source(src_filename)
        PLUGIN_DIR.mkdir(parents=True, exist_ok=True)
        dest = PLUGIN_DIR / dest_filename
        shutil.copy2(src, dest)
        dest.chmod(0o755)
        installed.append(dest)
    return installed
