#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Worker PID management, agent registry, task patching, and local JSON helpers.

Split from task_ops.py for Law 7 compliance.
Used by: pulse_worker.py, autopilot/loop.py
"""
from __future__ import annotations

import json
from pathlib import Path

from pulse.core.brain_utils import (
    STATE_DIR, WORKER_PIDS_FILE,
    now_iso as _now_iso,
)

# Lazy-loaded atomic updater
_atomic_update_json = None
_atomic_loaded = False


def _get_atomic_update():
    global _atomic_update_json, _atomic_loaded
    if not _atomic_loaded:
        _atomic_loaded = True
        try:
            from pulse.core.brain_utils import atomic_update_json
            _atomic_update_json = atomic_update_json
        except ImportError:
            _atomic_update_json = None
    return _atomic_update_json


AGENT_REGISTRY_FILE = STATE_DIR / "agent_registry.json"


def load_worker_pids() -> list[dict]:
    if not WORKER_PIDS_FILE.exists():
        return []
    try:
        data = json.loads(WORKER_PIDS_FILE.read_text(encoding="utf-8"))
        return data if isinstance(data, list) else []
    except Exception:
        return []


def save_worker_pids(records: list[dict]):
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    WORKER_PIDS_FILE.write_text(json.dumps(records, indent=2), encoding="utf-8")


def update_registry(worker_id: str, status: str = "idle",
                    task_id: str | None = None, domain: str | None = None):
    """Update agent registry: set status, track task completion."""
    atomic = _get_atomic_update()
    if not atomic:
        return

    now = _now_iso()

    def _update(reg):
        if worker_id not in reg:
            return reg
        reg[worker_id]["status"] = status
        reg[worker_id]["current_task"] = task_id
        reg[worker_id]["last_heartbeat"] = now
        if status == "idle" and domain:
            hist = reg[worker_id].setdefault("history", {"tasks_completed": 0, "domains": {}})
            hist["tasks_completed"] = hist.get("tasks_completed", 0) + 1
            hist["domains"][domain] = hist.get("domains", {}).get(domain, 0) + 1
        return reg
    atomic(AGENT_REGISTRY_FILE, _update, default={})


def patch_task_description(board_path: Path, task_id: str, suffix: str):
    """Append corrective constraint to a task's description for retry.

    Used by autopilot loop to inject gate failure feedback into reopened tasks.
    """
    atomic = _get_atomic_update()
    if not atomic:
        return

    def _update(board):
        if not isinstance(board, dict):
            return board
        for d in board.get("dispatches", []):
            for t in d.get("tasks", []):
                tid = t.get("task_id") or t.get("id", "")
                if tid == task_id:
                    desc = t.get("description", "")
                    if suffix.strip() not in desc:
                        t["description"] = desc + suffix
                    return board
        return board
    atomic(board_path, _update, default={})


def load_json(path: Path) -> dict:
    """Load JSON file, return empty dict on failure."""
    try:
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return {}
