# retoor <retoor@molodetz.nl>

import json
import logging
from datetime import datetime, timedelta, timezone

from devplacepy.database import db, get_table
from devplacepy.utils import generate_uid

logger = logging.getLogger(__name__)

PENDING = "pending"
RUNNING = "running"
DONE = "done"
FAILED = "failed"


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _table():
    return get_table("jobs")


def _decode(field: str) -> dict:
    if not field:
        return {}
    try:
        return json.loads(field)
    except (ValueError, TypeError):
        return {}


def _hydrate(row: dict) -> dict:
    row = dict(row)
    row["payload"] = _decode(row.get("payload"))
    row["result"] = _decode(row.get("result"))
    return row


def enqueue(
    kind: str, payload: dict, owner_kind: str, owner_id: str, preferred_name: str = ""
) -> str:
    uid = generate_uid()
    now = _now()
    _table().insert(
        {
            "uid": uid,
            "kind": kind,
            "status": PENDING,
            "owner_kind": owner_kind,
            "owner_id": owner_id,
            "preferred_name": preferred_name,
            "payload": json.dumps(payload),
            "result": "",
            "error": "",
            "retry_count": 0,
            "created_at": now,
            "started_at": "",
            "completed_at": "",
            "updated_at": now,
            "duration_ms": 0,
            "last_accessed_at": "",
            "expires_at": "",
            "bytes_in": 0,
            "bytes_out": 0,
            "item_count": 0,
        }
    )
    logger.info("Enqueued %s job %s for %s/%s", kind, uid, owner_kind, owner_id)
    return uid


def get_job(uid: str) -> dict | None:
    if "jobs" not in db.tables:
        return None
    row = _table().find_one(uid=uid)
    return _hydrate(row) if row else None


def touch_job(uid: str, extend_seconds: int) -> None:
    if "jobs" not in db.tables:
        return
    row = _table().find_one(uid=uid)
    if not row:
        return
    now = datetime.now(timezone.utc)
    _table().update(
        {
            "uid": uid,
            "last_accessed_at": now.isoformat(),
            "expires_at": (now + timedelta(seconds=extend_seconds)).isoformat(),
            "updated_at": now.isoformat(),
        },
        ["uid"],
    )


def list_jobs(kind: str = None, status: str = None, owner: tuple = None) -> list[dict]:
    if "jobs" not in db.tables:
        return []
    filters = {}
    if kind:
        filters["kind"] = kind
    if status:
        filters["status"] = status
    if owner:
        filters["owner_kind"], filters["owner_id"] = owner
    return [_hydrate(row) for row in _table().find(**filters)]
