# retoor <retoor@molodetz.nl>

import logging
from typing import Any
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, JSONResponse
from devplacepy.templating import templates
from devplacepy.utils import require_admin, not_found
from devplacepy.services.manager import service_manager
from devplacepy.seo import base_seo_context, site_url, website_schema
from devplacepy.services.audit import record as audit

logger = logging.getLogger(__name__)
router = APIRouter()


@router.get("", response_class=HTMLResponse)
async def services_page(request: Request):
    admin = require_admin(request)
    services = service_manager.describe_all()
    base = site_url(request)
    seo_ctx = base_seo_context(
        request,
        title="Services - Admin",
        description="Monitor and configure background services on DevPlace.",
        robots="noindex,nofollow",
        breadcrumbs=[
            {"name": "Home", "url": "/feed"},
            {"name": "Admin", "url": "/admin"},
            {"name": "Services", "url": "/admin/services"},
        ],
        schemas=[website_schema(base)],
    )
    return templates.TemplateResponse(
        request,
        "services.html",
        {
            **seo_ctx,
            "request": request,
            "user": admin,
            "services": services,
            "admin_section": "services",
        },
    )


@router.get("/data")
async def services_json(request: Request):
    require_admin(request)
    return JSONResponse({"services": service_manager.describe_all()})


@router.get("/{name}", response_class=HTMLResponse)
async def service_detail(request: Request, name: str):
    admin = require_admin(request)
    svc = service_manager.get_service(name)
    if svc is None:
        raise not_found("Service not found")
    info = svc.describe()
    base = site_url(request)
    seo_ctx = base_seo_context(
        request,
        title=f"{info['title']} - Services",
        description=info["description"] or f"Configure the {info['title']} service.",
        robots="noindex,nofollow",
        breadcrumbs=[
            {"name": "Home", "url": "/feed"},
            {"name": "Admin", "url": "/admin"},
            {"name": "Services", "url": "/admin/services"},
            {"name": info["title"], "url": f"/admin/services/{name}"},
        ],
        schemas=[website_schema(base)],
    )
    return templates.TemplateResponse(
        request,
        "service_detail.html",
        {
            **seo_ctx,
            "request": request,
            "user": admin,
            "service": info,
            "admin_section": "services",
        },
    )


@router.get("/{name}/data")
async def service_detail_json(request: Request, name: str):
    require_admin(request)
    svc = service_manager.get_service(name)
    if svc is None:
        return JSONResponse({"error": "unknown service"}, status_code=404)
    return JSONResponse({"service": svc.describe()})


def _audit_service(request: Request, admin: dict, name: str, event_key: str, summary: str, **kwargs: Any) -> None:
    audit.record(
        request,
        event_key,
        user=admin,
        target_type="service",
        target_uid=name,
        target_label=name,
        summary=summary,
        links=[audit.service_link(name)],
        **kwargs,
    )


@router.post("/{name}/start")
async def service_start(request: Request, name: str):
    admin = require_admin(request)
    if not service_manager.set_enabled(name, True):
        return JSONResponse({"ok": False, "error": "unknown service"}, status_code=404)
    _audit_service(
        request, admin, name, "service.start",
        f"admin {admin['username']} started service {name}", new_value="enabled",
    )
    return JSONResponse({"ok": True})


@router.post("/{name}/stop")
async def service_stop(request: Request, name: str):
    admin = require_admin(request)
    if not service_manager.set_enabled(name, False):
        return JSONResponse({"ok": False, "error": "unknown service"}, status_code=404)
    _audit_service(
        request, admin, name, "service.stop",
        f"admin {admin['username']} stopped service {name}", new_value="disabled",
    )
    return JSONResponse({"ok": True})


@router.post("/{name}/run")
async def service_run(request: Request, name: str):
    admin = require_admin(request)
    if not service_manager.send_command(name, "run"):
        return JSONResponse({"ok": False, "error": "unknown service"}, status_code=404)
    _audit_service(
        request, admin, name, "service.run_now",
        f"admin {admin['username']} triggered an immediate run of service {name}",
    )
    return JSONResponse({"ok": True})


@router.post("/{name}/clear-logs")
async def service_clear_logs(request: Request, name: str):
    admin = require_admin(request)
    if not service_manager.send_command(name, "clear"):
        return JSONResponse({"ok": False, "error": "unknown service"}, status_code=404)
    _audit_service(
        request, admin, name, "service.logs.clear",
        f"admin {admin['username']} cleared logs for service {name}",
    )
    return JSONResponse({"ok": True})


@router.post("/{name}/config")
async def service_config(request: Request, name: str):
    admin = require_admin(request)
    svc = service_manager.get_service(name)
    before = svc.get_config() if svc is not None else {}
    form = await request.form()
    result = service_manager.save_config(name, dict(form))
    if result is None:
        return JSONResponse({"ok": False, "error": "unknown service"}, status_code=404)
    after = svc.get_config() if svc is not None else {}
    for key, new_value in after.items():
        old_value = before.get(key)
        if old_value == new_value:
            continue
        audit.record(
            request,
            "service.config.update",
            user=admin,
            target_type="service",
            target_uid=name,
            target_label=name,
            old_value=old_value,
            new_value=new_value,
            summary=f"admin {admin['username']} updated {key} of service {name}",
            links=[audit.service_link(name), audit.setting(key)],
        )
    if not result["ok"]:
        return JSONResponse(result, status_code=400)
    return JSONResponse(result)
