"""Cron routes: /cron/jobs CRUD + enable/disable/run."""

from __future__ import annotations

try:
    from aiohttp import web  # noqa: F401
except ImportError as _exc:
    raise RuntimeError("aiohttp is required for gateway routes (pip install aiohttp)") from _exc
from navig.debug_logger import get_debug_logger
from navig.gateway.routes.common import (
    json_error_response,
    json_ok,
    require_bearer_auth,
)

logger = get_debug_logger()


def register(app, gateway):
    app.router.add_get("/cron/jobs", _list(gateway))
    app.router.add_post("/cron/jobs", _add(gateway))
    app.router.add_get("/cron/jobs/{job_id}", _get(gateway))
    app.router.add_delete("/cron/jobs/{job_id}", _delete(gateway))
    app.router.add_post("/cron/jobs/{job_id}/enable", _enable(gateway))
    app.router.add_post("/cron/jobs/{job_id}/disable", _disable(gateway))
    app.router.add_post("/cron/jobs/{job_id}/run", _run(gateway))


def _svc_or_503(gw):
    if not gw.cron_service:
        return None, json_error_response(
            "Cron service not enabled", status=503, code="module_unavailable"
        )
    return gw.cron_service, None


def _list(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            jobs = cs.list_jobs()
            return json_ok({"jobs": [j.to_dict() for j in jobs]})
        except Exception as e:
            logger.exception("Failed to list cron jobs")
            return json_error_response(
                "Failed to list cron jobs",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _add(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            data = await r.json()
            job = cs.add_job(
                name=data["name"],
                schedule=data["schedule"],
                command=data["command"],
                enabled=data.get("enabled", True),
                timeout_seconds=data.get("timeout", 300),
            )
            return json_ok(job.to_dict())
        except KeyError as e:
            return json_error_response(
                f"Missing required field: {e}", status=400, code="validation_error"
            )
        except Exception as e:
            logger.exception("Failed to create cron job")
            return json_error_response(
                "Failed to create cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _get(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            job = cs.get_job(r.match_info["job_id"])
            if not job:
                return json_error_response("Job not found", status=404, code="not_found")
            return json_ok(job.to_dict())
        except Exception as e:
            logger.exception("Failed to get cron job")
            return json_error_response(
                "Failed to get cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _delete(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            ok = cs.remove_job(r.match_info["job_id"])
            if not ok:
                return json_error_response("Job not found", status=404, code="not_found")
            return json_ok({"deleted": True})
        except Exception as e:
            logger.exception("Failed to delete cron job")
            return json_error_response(
                "Failed to delete cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _enable(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            ok = cs.enable_job(r.match_info["job_id"])
            if not ok:
                return json_error_response("Job not found", status=404, code="not_found")
            return json_ok({"enabled": True})
        except Exception as e:
            logger.exception("Failed to enable cron job")
            return json_error_response(
                "Failed to enable cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _disable(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            ok = cs.disable_job(r.match_info["job_id"])
            if not ok:
                return json_error_response("Job not found", status=404, code="not_found")
            return json_ok({"disabled": True})
        except Exception as e:
            logger.exception("Failed to disable cron job")
            return json_error_response(
                "Failed to disable cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h


def _run(gw):
    async def h(r):
        auth = require_bearer_auth(r, gw)
        if auth is not None:
            return auth
        cs, err = _svc_or_503(gw)
        if err:
            return err
        try:
            result = await cs.run_job_now(r.match_info["job_id"])
            if not result:
                return json_error_response("Job not found", status=404, code="not_found")
            return json_ok(
                {
                    "success": result.get("success", False),
                    "output": result.get("output", ""),
                    "error": result.get("error"),
                }
            )
        except Exception as e:
            logger.exception("Failed to run cron job")
            return json_error_response(
                "Failed to run cron job",
                status=500,
                code="internal_error",
                details={"error": str(e)},
            )

    return h
