from __future__ import annotations

from fastapi import Request as FRequest
from fastapi.responses import JSONResponse


def register_plugin_routes(
    fastapi_app,
    delegate,
    app_http_routes=None,
    auth_token: str | None = None,
    plugins_for_api=None,
    clear_dashboard_manifest_cache=None,
    require_dashboard_slug=None,
) -> None:
    @fastapi_app.get("/preferences/plugins")
    async def list_plugins():
        if not callable(plugins_for_api):
            return JSONResponse(content=[])
        try:
            return JSONResponse(content=plugins_for_api(delegate._plugin_manager))
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)[:200]}, status_code=500)

    @fastapi_app.post("/preferences/plugins/{slug}/toggle")
    async def toggle_plugin(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            from plugin_security import get_plugin_approval_state

            entry = pm._discovered_manifests.get(slug)
            if not entry:
                return JSONResponse(content={"error": "not found"}, status_code=404)
            manifest, _ = entry
            state = get_plugin_approval_state(slug)
            enabled = state.get("enabled", False)
            if enabled:
                pm.disable_plugin(manifest.name)
                return JSONResponse(content={"ok": True, "enabled": False})
            pm.enable_plugin(manifest.name)
            if app_http_routes is not None:
                app_http_routes.mount_plugin_http_routes(fastapi_app, delegate, auth_token)
            return JSONResponse(content={"ok": True, "enabled": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.post("/preferences/plugins/{slug}/remove")
    async def remove_plugin(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            if slug not in pm._discovered_manifests:
                return JSONResponse(content={"error": "not found"}, status_code=404)
            pm.remove_plugin(slug)
            return JSONResponse(content={"ok": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.post("/preferences/plugins/reload")
    async def reload_plugins():
        """Re-discover plugins from disk and return the updated list."""
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            pm.reload_all()
            if callable(clear_dashboard_manifest_cache):
                clear_dashboard_manifest_cache()
            if app_http_routes is not None:
                app_http_routes.mount_plugin_http_routes(fastapi_app, delegate, auth_token)
            if callable(plugins_for_api):
                return JSONResponse(content=plugins_for_api(pm))
            return JSONResponse(content={"ok": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.post("/preferences/dashboard-plugins/{slug}/toggle")
    async def toggle_dashboard_plugin(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        if callable(require_dashboard_slug):
            bad = require_dashboard_slug(pm, slug)
            if bad is not None:
                return bad
        try:
            from plugin_security import get_plugin_approval_state

            entry = pm._discovered_manifests.get(slug)
            manifest, _ = entry
            state = get_plugin_approval_state(slug)
            enabled = state.get("enabled", False)
            if enabled:
                pm.disable_plugin(manifest.name)
                if callable(clear_dashboard_manifest_cache):
                    clear_dashboard_manifest_cache()
                return JSONResponse(content={"ok": True, "enabled": False})
            pm.enable_plugin(manifest.name)
            if app_http_routes is not None:
                app_http_routes.mount_plugin_http_routes(fastapi_app, delegate, auth_token)
            if callable(clear_dashboard_manifest_cache):
                clear_dashboard_manifest_cache()
            return JSONResponse(content={"ok": True, "enabled": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.post("/preferences/dashboard-plugins/{slug}/remove")
    async def remove_dashboard_plugin(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        if callable(require_dashboard_slug):
            bad = require_dashboard_slug(pm, slug)
            if bad is not None:
                return bad
        try:
            pm.remove_plugin(slug)
            if callable(clear_dashboard_manifest_cache):
                clear_dashboard_manifest_cache()
            return JSONResponse(content={"ok": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.post("/preferences/dashboard-plugins/reload")
    async def reload_dashboard_plugins():
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            pm.reload_all()
            if callable(clear_dashboard_manifest_cache):
                clear_dashboard_manifest_cache()
            if app_http_routes is not None:
                app_http_routes.mount_plugin_http_routes(fastapi_app, delegate, auth_token)
            if callable(plugins_for_api):
                return JSONResponse(content=plugins_for_api(pm, dashboard_only=True))
            return JSONResponse(content={"ok": True})
        except Exception as exc:
            return JSONResponse(content={"error": str(exc)}, status_code=500)

    @fastapi_app.put("/preferences/dashboard-plugins/{slug}/settings")
    async def put_dashboard_plugin_settings(slug: str, request: FRequest):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        if callable(require_dashboard_slug):
            bad = require_dashboard_slug(pm, slug)
            if bad is not None:
                return bad
        try:
            body = await request.json()
        except Exception:
            body = {}
        if not isinstance(body, dict):
            return JSONResponse(content={"error": "invalid JSON"}, status_code=400)
        updates = body.get("settings")
        if not isinstance(updates, dict):
            return JSONResponse(
                content={"error": "body must include a settings object"},
                status_code=400,
            )
        from plugin_security import (
            effective_plugin_settings,
            merge_plugin_settings_payload,
            save_plugin_settings_values,
        )

        schema = pm.get_settings_schema(slug)
        coerced, err = merge_plugin_settings_payload(schema, updates)
        if err:
            return JSONResponse(content={"error": err}, status_code=400)
        merged = save_plugin_settings_values(slug, coerced, schema=schema)
        full = effective_plugin_settings(schema, merged)
        try:
            pm.sync_runtime_settings(slug, full)
        except Exception:
            pass
        return JSONResponse(content={"ok": True, "settings": full})

    @fastapi_app.post("/preferences/plugins/sandbox/rollback")
    async def sandbox_rollback():
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        state = pm.rollback_sandbox_state()
        return JSONResponse(content={"ok": True, "state": state})

    @fastapi_app.post("/preferences/plugins/sandbox/kill_switch")
    async def sandbox_kill_switch(request: FRequest):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            body = await request.json()
        except Exception:
            body = {}
        enabled = bool((body or {}).get("enabled", False))
        pm.set_sandbox_kill_switch(enabled)
        return JSONResponse(content={"ok": True, "enabled": enabled})

    @fastapi_app.post("/preferences/plugins/{slug}/quarantine")
    async def quarantine_plugin(slug: str, request: FRequest):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        try:
            body = await request.json()
        except Exception:
            body = {}
        reason = str((body or {}).get("reason") or "quarantined by operator")
        pm.quarantine_plugin(slug, reason)
        return JSONResponse(content={"ok": True, "slug": slug, "reason": reason})

    @fastapi_app.post("/preferences/plugins/{slug}/unquarantine")
    async def unquarantine_plugin(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        pm.clear_quarantine(slug)
        return JSONResponse(content={"ok": True, "slug": slug})

    @fastapi_app.post("/preferences/plugins/{slug}/runtime/restart")
    async def restart_plugin_runtime(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        out = pm.restart_plugin_runtime(slug)
        if not out.get("ok"):
            return JSONResponse(content=out, status_code=500)
        return JSONResponse(content=out)

    @fastapi_app.get("/preferences/plugins/{slug}/runtime/crash_dump")
    async def plugin_runtime_crash_dump(slug: str):
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        out = pm.capture_runtime_crash_dump(slug)
        if not out.get("ok"):
            return JSONResponse(content=out, status_code=404)
        return JSONResponse(content=out)

    @fastapi_app.get("/preferences/plugins/sandbox/route_support")
    async def sandbox_route_support():
        return JSONResponse(
            content={
                "transport": "stdio-jsonl-v1",
                "phase1": {
                    "json_request_response": True,
                    "sse_passthrough": True,
                    "chunked_stream_frames": True,
                },
                "phase2": {
                    "websocket_proxy": False,
                    "reason": "intentionally disabled pending explicit enablement",
                },
                "limits": {
                    "max_request_body_bytes": 1024 * 1024,
                    "max_response_body_bytes": 2 * 1024 * 1024,
                    "max_headers": 64,
                },
            }
        )

    @fastapi_app.put("/preferences/plugins/{slug}/settings")
    async def put_plugin_settings(slug: str, request: FRequest):
        """Merge validated settings into ~/.mugi/app_prefs.json for one plugin."""
        pm = delegate._plugin_manager
        if pm is None:
            return JSONResponse(content={"error": "no plugin manager"}, status_code=500)
        if slug not in pm._discovered_manifests:
            return JSONResponse(content={"error": "not found"}, status_code=404)
        try:
            body = await request.json()
        except Exception:
            body = {}
        if not isinstance(body, dict):
            return JSONResponse(content={"error": "invalid JSON"}, status_code=400)
        updates = body.get("settings")
        if not isinstance(updates, dict):
            return JSONResponse(
                content={"error": "body must include a settings object"},
                status_code=400,
            )
        from plugin_security import (
            effective_plugin_settings,
            merge_plugin_settings_payload,
            save_plugin_settings_values,
        )

        schema = pm.get_settings_schema(slug)
        coerced, err = merge_plugin_settings_payload(schema, updates)
        if err:
            return JSONResponse(content={"error": err}, status_code=400)
        merged = save_plugin_settings_values(slug, coerced, schema=schema)
        full = effective_plugin_settings(schema, merged)
        try:
            pm.sync_runtime_settings(slug, full)
        except Exception:
            pass
        return JSONResponse(content={"ok": True, "settings": full})

