"""Tarefa bounded para cron do cPanel; usa o mesmo JSON privado do Passenger."""

import argparse
import fcntl
import json
import os
import time
from pathlib import Path
from app.db import connect
from app.worker import run_once
from app.events import deliver_events


def process_pending(db, budget=40, max_jobs=100, watch=False):
    started = time.monotonic()
    result = {"messages": 0, "events": 0, "skipped": False}
    lock_path = Path(db).parent / "worker.lock"
    lock_path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    with lock_path.open("a+") as lock:
        os.chmod(lock_path, 0o600)
        try:
            fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except BlockingIOError:
            return dict(result, skipped=True)

        def heartbeat(status):
            with connect(db, True) as c:
                c.execute(
                    "insert into runtime_health values('worker',?,?) on conflict(key) do update set value=excluded.value,updated=excluded.updated",
                    (json.dumps({"status": status}), time.time()),
                )

        heartbeat("running")
        try:
            while (
                time.monotonic() - started < budget
                and sum((result["messages"], result["events"])) < max_jobs
            ):
                worked = run_once(db)
                result["messages"] += worked
                hooked = 0
                if (
                    time.monotonic() - started < budget
                    and result["messages"] + result["events"] < max_jobs
                ):
                    hooked = deliver_events(db)
                    result["events"] += hooked
                if not worked and not hooked:
                    if watch:
                        time.sleep(
                            min(1, max(0, budget - (time.monotonic() - started)))
                        )
                    else:
                        break
            heartbeat("ok")
        except BaseException:
            heartbeat("error")
            raise
    return result


def main():
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument("--budget", type=int, default=40)
    p.add_argument("--max-jobs", type=int, default=100)
    p.add_argument("--loop", action="store_true")
    p.add_argument("--watch", action="store_true")
    args = p.parse_args()
    if not 1 <= args.budget <= 50 or not 1 <= args.max_jobs <= 1000:
        p.error("budget: 1–50 segundos; max-jobs: 1–1000")
    from deployment import create_server_app

    a = create_server_app()
    while True:
        try:
            result = process_pending(
                a.config["DATABASE"], args.budget, args.max_jobs, watch=args.watch
            )
        except Exception:
            print(
                json.dumps(
                    {
                        "status": "error",
                        "message": "Falha no processador. Verifique o log privado e as permissões.",
                    }
                ),
                flush=True,
            )
            raise SystemExit(1)
        print(json.dumps({"status": "ok", **result}), flush=True)
        if not args.loop:
            break
        time.sleep(1)


if __name__ == "__main__":
    main()
