#!/usr/bin/env python3
"""Fix paperclipai/* skill drift across CMP+CMPA agents.

Goal: zero drift on paperclipai/* skills between master(CMP) and mirror(CMPA).

Rules:
* Remove ``paperclipai/paperclip/paperclip-dev`` from all 14 agents (not relevant
  for legal work — it's for maintaining Paperclip itself).
* Ensure ``paperclipai/paperclip/paperclip-converting-plans-to-tasks`` exists
  on CEO + analyst agents in both companies (planning skill).
* Remove ``paperclipai/paperclip/paperclip-converting-plans-to-tasks`` from any
  other agent in either company that currently has it.

Local/* and company/* skills are not touched — they're scoped to a company
by design and drift is expected.

Usage::

    PAPERCLIP_BOARD_API_KEY=pbk_... python scripts/fix_paperclipai_skills_drift.py            # dry-run
    PAPERCLIP_BOARD_API_KEY=pbk_... python scripts/fix_paperclipai_skills_drift.py --apply    # commit
"""

from __future__ import annotations

import argparse
import asyncio
import os
import sys

import httpx

PAPERCLIP_API_URL = os.environ.get("PAPERCLIP_API_URL", "http://localhost:3100")
PAPERCLIP_BOARD_API_KEY = os.environ.get("PAPERCLIP_BOARD_API_KEY")

COMPANIES = {
    "licensing": ("CMP ", "42a7acd0-30c5-4cbd-ac97-7424f65df294"),
    "betterment": ("CMPA", "8639e837-4c9d-47fa-a76b-95788d651896"),
}

DEV_SKILL = "paperclipai/paperclip/paperclip-dev"
CONVERTING_SKILL = "paperclipai/paperclip/paperclip-converting-plans-to-tasks"

# Hebrew names of the agents that should retain converting-plans-to-tasks.
CONVERTING_TARGETS = {"עוזר משפטי", "מנתח משפטי"}


def headers() -> dict[str, str]:
    if not PAPERCLIP_BOARD_API_KEY:
        sys.exit("PAPERCLIP_BOARD_API_KEY not set — fetch from Infisical first.")
    return {
        "Authorization": f"Bearer {PAPERCLIP_BOARD_API_KEY}",
        "Content-Type": "application/json",
    }


async def fetch_company_agents(client: httpx.AsyncClient, company_id: str) -> list[dict]:
    r = await client.get(f"{PAPERCLIP_API_URL}/api/companies/{company_id}/agents", headers=headers())
    r.raise_for_status()
    return r.json()


def compute_changes(agent: dict) -> tuple[bool, list[str], list[str]]:
    skill_sync = (agent.get("adapterConfig") or {}).get("paperclipSkillSync") or {}
    old = list(skill_sync.get("desiredSkills") or [])
    new = [s for s in old if s != DEV_SKILL]
    if agent["name"] in CONVERTING_TARGETS:
        if CONVERTING_SKILL not in new:
            new.append(CONVERTING_SKILL)
    else:
        new = [s for s in new if s != CONVERTING_SKILL]
    return (sorted(old) != sorted(new), old, new)


async def patch_agent(
    client: httpx.AsyncClient, agent_id: str, current_skill_sync: dict, new_skills: list[str]
) -> None:
    body = {
        "adapterConfig": {
            "paperclipSkillSync": {**current_skill_sync, "desiredSkills": new_skills},
        }
    }
    r = await client.patch(
        f"{PAPERCLIP_API_URL}/api/agents/{agent_id}", headers=headers(), json=body, timeout=15
    )
    r.raise_for_status()


async def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--apply", action="store_true", help="commit changes (default: dry-run)")
    args = parser.parse_args()

    mode = "APPLY" if args.apply else "DRY-RUN"
    print(f"=== {mode}: fixing paperclipai/* skill drift ===\n")

    async with httpx.AsyncClient(timeout=15) as client:
        all_agents: list[dict] = []
        for label, (_, cid) in COMPANIES.items():
            agents = await fetch_company_agents(client, cid)
            for a in agents:
                a["_company_label"] = COMPANIES[label][0]
            all_agents.extend(agents)

        changes_planned = 0
        for a in sorted(all_agents, key=lambda x: (x["_company_label"], x["name"])):
            changed, old, new = compute_changes(a)
            label = a["_company_label"]
            if not changed:
                print(f"  {label}  {a['name']:20}  no change")
                continue
            changes_planned += 1
            removed = sorted(set(old) - set(new))
            added = sorted(set(new) - set(old))
            print(f"  {label}  {a['name']:20}  -{len(removed)} +{len(added)}")
            for s in removed:
                print(f"    - {s}")
            for s in added:
                print(f"    + {s}")
            if args.apply:
                skill_sync = (a.get("adapterConfig") or {}).get("paperclipSkillSync") or {}
                try:
                    await patch_agent(client, a["id"], skill_sync, new)
                    print("    ✓ patched")
                except httpx.HTTPStatusError as e:
                    print(f"    ✗ failed: {e.response.status_code} {e.response.text[:200]}")
                    raise

        print(f"\n{mode}: {changes_planned} agents would change")
        if not args.apply and changes_planned > 0:
            print("Run with --apply to commit.")


if __name__ == "__main__":
    asyncio.run(main())
