#!/bin/sh
# A small service whose live code is reached dynamically: getattr dispatch, importlib plugins,
# a decorator registry, pyproject entry points, a Flask route, and a plugin named only in config.
set -e
mkdir -p src/svc/plugins
: > src/svc/__init__.py; : > src/svc/plugins/__init__.py
cat > pyproject.toml <<'EOF'
[project]
name = "svc"
version = "0.1.0"
dependencies = ["flask==3.1.2"]

[project.scripts]
svc-admin = "svc.cli:main"

[project.entry-points."svc.exporters"]
csv = "svc.exporters:export_csv"
EOF
cat > plugins.toml <<'EOF'
[billing]
module = "svc.plugins.billing"
entry = "billing_ready"
EOF
cat > src/svc/cli.py <<'EOF'
def main():
    print("admin cli")
EOF
cat > src/svc/config_loader.py <<'EOF'
import importlib
import tomllib

def load_all(path="plugins.toml"):
    with open(path, "rb") as f:
        cfg = tomllib.load(f)
    return [getattr(importlib.import_module(p["module"]), p["entry"])() for p in cfg.values()]

if __name__ == "__main__":
    print(load_all())
EOF
cat > src/svc/dispatch.py <<'EOF'
class Commands:
    """Handlers are looked up by name at runtime: handle_<action>."""

    def run(self, action):
        return getattr(self, f"handle_{action}")()

    def handle_start(self):
        return "starting"

    def handle_stop(self):
        return "stopping"

    def handle_legacy_reindex(self):
        # no action string anywhere maps to "legacy_reindex": truly dead
        return "reindexing"
EOF
cat > src/svc/exporters.py <<'EOF'
def export_csv(rows):
    return "\n".join(",".join(map(str, r)) for r in rows)
EOF
cat > src/svc/loader.py <<'EOF'
import importlib

def load(name):
    # plugin name comes from config at runtime, e.g. "audit"
    mod = importlib.import_module(f"svc.plugins.{name}")
    return mod.register()
EOF
cat > src/svc/main.py <<'EOF'
from svc.dispatch import Commands
from svc.loader import load
from svc.registry import fire

if __name__ == "__main__":
    print(Commands().run("start"), load("audit"), fire("on_login", "scott"))
EOF
cat > src/svc/plugins/audit.py <<'EOF'
def register():
    return "audit plugin registered"
EOF
cat > src/svc/plugins/billing.py <<'EOF'
def billing_ready():
    # named only in plugins.toml; the loader reads the name from config
    return "billing plugin ready"
EOF
cat > src/svc/registry.py <<'EOF'
HOOKS = {}

def hook(name):
    def deco(fn):
        HOOKS[name] = fn
        return fn
    return deco

@hook("on_login")
def record_login(user):
    return f"login {user}"

def fire(name, *args):
    return HOOKS[name](*args)
EOF
cat > src/svc/truly_dead.py <<'EOF'
def old_report():
    # the only function in this repo that nothing reaches, statically or at runtime
    return "nobody calls me"
EOF
cat > src/svc/web.py <<'EOF'
from flask import Flask

app = Flask(__name__)

@app.route("/health")
def health():
    return "ok"
EOF
git init -q && git add -A && git -c user.email=lab@example.com -c user.name=lab commit -qm init
