#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
swarm_evolution.py — A4 双层协同演进（吸收 openJiuwen 团队层 + 成员层双层演进）
========================================================================================
把"团队编排真值"与"Teammate 个人经验"拆成两个独立真值域，各自独立演进，
避免团队层与成员层相互污染。两层都走 T0 人工审批锁档，不自动生效。

- TeamLayer   ：团队编排真值（流程模板、分工策略、协作约束、Leader 逻辑）
- MemberLayer ：成员经验（Teammate 擅长、失败轨迹、个人 prompt 调整）
- 两层 propose → 入评审队列 → approve 才沉淀，版本链独立可回滚
"""

import json
import os
import uuid
from datetime import datetime

ANCHOR = "Ω₀⊂⊙∞⊂Ω"
DID = "DID-BR-000002"
EVO_DB = os.environ.get("SWARM_EVO_DB", "/var/lib/zr-swarm/evolution.json")

# 双层真值域
LAYERS = {"team": "团队编排真值域", "member": "成员经验真值域"}


def now():
    return datetime.now().isoformat(timespec="seconds")


def _load_json(path, default):
    try:
        if os.path.exists(path):
            with open(path, "r", encoding="utf-8") as f:
                return json.load(f)
    except Exception:
        pass
    return default


def _save_json(path, obj):
    os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
    tmp = path + ".tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        json.dump(obj, f, ensure_ascii=False, indent=2)
    os.replace(tmp, path)


class DualLayerEvolution:
    """双层协同演进：团队层与成员层独立演进。"""

    def __init__(self):
        self.db = _load_json(EVO_DB, {"team": {"queue": [], "versions": []},
                                      "member": {"queue": [], "versions": []}})
        for ly in LAYERS:
            self.db.setdefault(ly, {"queue": [], "versions": []})

    def propose(self, layer, subject, lesson, reason_trace, domain):
        """候选演进建议（pending，待 T0 审批）。"""
        if layer not in LAYERS:
            return {"ok": False, "error": f"unknown_layer:{layer}"}
        cand = {
            "evo_id": f"EVO-{layer[:1].upper()}-{uuid.uuid4().hex[:8].upper()}",
            "layer": layer, "subject": subject, "lesson": lesson,
            "reason_trace": reason_trace, "domain": domain,
            "status": "pending_t0_review", "created": now(),
            "did": DID, "anchor": ANCHOR,
        }
        self.db[layer]["queue"].append(cand)
        _save_json(EVO_DB, self.db)
        return {"ok": True, "evo_id": cand["evo_id"], "layer": layer,
                "queue_size": len(self.db[layer]["queue"])}

    def approve(self, evo_id, reviewer="human"):
        ly = self._find_layer(evo_id)
        if not ly:
            return {"ok": False, "error": "evo_not_found"}
        q = self.db[ly]
        target = next((c for c in q["queue"] if c["evo_id"] == evo_id), None)
        if not target:
            return {"ok": False, "error": "evo_not_in_queue"}
        q["queue"] = [c for c in q["queue"] if c["evo_id"] != evo_id]
        target["status"] = "approved"
        target["reviewer"] = reviewer
        target["approved_at"] = now()
        q["versions"].append(target)   # 版本链独立
        _save_json(EVO_DB, self.db)
        return {"ok": True, "evo_id": evo_id, "layer": ly, "versions": len(q["versions"])}

    def reject(self, evo_id, reviewer="human"):
        ly = self._find_layer(evo_id)
        if not ly:
            return {"ok": False, "error": "evo_not_found"}
        q = self.db[ly]
        q["queue"] = [c for c in q["queue"] if c["evo_id"] != evo_id]
        _save_json(EVO_DB, self.db)
        return {"ok": True, "evo_id": evo_id, "status": "rejected"}

    def _find_layer(self, evo_id):
        for ly in LAYERS:
            if any(c["evo_id"] == evo_id for c in self.db[ly]["queue"]) or \
               any(v["evo_id"] == evo_id for v in self.db[ly]["versions"]):
                return ly
        return None

    def recall(self, layer, domain=None, trust="T0"):
        """编排器召回已生效的演进真值。"""
        if layer not in LAYERS:
            return []
        out = list(self.db[layer]["versions"])
        if domain:
            out = [v for v in out if v.get("domain") == domain]
        return out

    def stats(self):
        return {
            "team": {"pending": len(self.db["team"]["queue"]),
                     "versions": len(self.db["team"]["versions"])},
            "member": {"pending": len(self.db["member"]["queue"]),
                       "versions": len(self.db["member"]["versions"])},
            "anchor": ANCHOR,
        }


def _demo():
    print("== A4 双层协同演进 demo ==")
    evo = DualLayerEvolution()
    c1 = evo.propose("team", "分工策略优化", "按任务复杂度动态拆3段优于固定2段", "三次对比实验", "agent")
    print("团队层候选:", c1["evo_id"], "| 入队:", c1["queue_size"])
    c2 = evo.propose("member", "Teammate-1 擅长长文分析", "实测完成度最高", "5次任务轨迹", "arch")
    print("成员层候选:", c2["evo_id"])
    evo.approve(c1["evo_id"], reviewer="demo")
    evo.approve(c2["evo_id"], reviewer="demo")
    print("双层统计:", json.dumps(evo.stats(), ensure_ascii=False))
    print("团队层召回:", [v["subject"] for v in evo.recall("team")])
    return evo.stats()


if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == "stats":
        print(json.dumps(DualLayerEvolution().stats(), ensure_ascii=False, indent=2))
    else:
        _demo()
