"""Phase 5D: Graduated Autonomy — trust ladder with promotion/demotion logic."""
import json
from datetime import datetime, timezone
from pathlib import Path
from pulse.core.paths import get_state_dir
from pulse.core import event_bus
from pulse.core.brain_io import _acquire

AUTONOMY_FILE = get_state_dir() / "autonomy_state.json"

LEVEL_NAMES = {0: "Witness", 1: "Apprentice", 2: "Journeyman", 3: "Artisan", 4: "Steward"}

PROMOTION_REQUIREMENTS = {
    0: {"successful_tasks": 20, "regressions": 0, "days": 7},
    1: {"successful_tasks": 50, "oracle_accuracy": 0.6, "days": 14},
    2: {"successful_tasks": 100, "demotions": 0, "days": 30},
    3: {"successful_tasks": 200, "human_audit": True, "days": 60},
}


def _load_state() -> dict:
    if not AUTONOMY_FILE.exists():
        return _default_state()
    try:
        return json.loads(AUTONOMY_FILE.read_text(encoding="utf-8"))
    except Exception:
        return _default_state()


def _save_state(state: dict):
    AUTONOMY_FILE.parent.mkdir(parents=True, exist_ok=True)
    with _acquire(AUTONOMY_FILE):
        AUTONOMY_FILE.write_text(json.dumps(state, indent=2), encoding="utf-8")


def _default_state() -> dict:
    return {
        "trust_level": 0,
        "current_level_name": "Witness",
        "promoted_at": datetime.now(timezone.utc).isoformat(),
        "history": [{"level": 0, "date": datetime.now(timezone.utc).isoformat(), "reason": "bootstrap"}],
        "metrics": {
            "successful_tasks": 0,
            "failed_tasks": 0,
            "regressions": 0,
            "demotions": 0,
            "consecutive_failures": 0,
        },
    }


def get_trust_level() -> int:
    """Return current trust level (0-4)."""
    return _load_state()["trust_level"]


def record_task_outcome(success: bool, regression: bool = False):
    """Record task outcome for promotion tracking."""
    state = _load_state()
    if success:
        state["metrics"]["successful_tasks"] += 1
        state["metrics"]["consecutive_failures"] = 0
    else:
        state["metrics"]["failed_tasks"] += 1
        state["metrics"]["consecutive_failures"] += 1
    if regression:
        state["metrics"]["regressions"] += 1
    _save_state(state)

    # Check demotion triggers
    if regression or state["metrics"]["consecutive_failures"] >= 3:
        _demote(state, "regression" if regression else "consecutive_failures")


def check_promotion() -> bool:
    """Check if promotion criteria met. Called by consolidation."""
    state = _load_state()
    level = state["trust_level"]
    if level >= 4:
        return False

    reqs = PROMOTION_REQUIREMENTS.get(level, {})
    metrics = state["metrics"]
    promoted_at = datetime.fromisoformat(state["promoted_at"])
    days_at_level = (datetime.now(timezone.utc) - promoted_at).days

    # Check all requirements
    if days_at_level < reqs.get("days", 0):
        return False
    if metrics["successful_tasks"] < reqs.get("successful_tasks", 0):
        return False
    if reqs.get("regressions") is not None and metrics["regressions"] > reqs["regressions"]:
        return False
    if reqs.get("human_audit") and not state.get("human_audit_passed"):
        return False

    # Promote
    state["trust_level"] = level + 1
    state["current_level_name"] = LEVEL_NAMES[level + 1]
    state["promoted_at"] = datetime.now(timezone.utc).isoformat()
    state["history"].append({
        "level": level + 1,
        "date": datetime.now(timezone.utc).isoformat(),
        "reason": "promotion",
    })
    state["metrics"]["regressions"] = 0
    state["metrics"]["consecutive_failures"] = 0
    _save_state(state)
    event_bus.publish(
        "autonomy.promoted", "autonomy_state",
        {"new_level": level + 1, "name": LEVEL_NAMES[level + 1]},
    )
    return True


def _demote(state: dict, reason: str):
    """Drop trust level by 1."""
    if state["trust_level"] <= 0:
        return
    state["trust_level"] -= 1
    state["current_level_name"] = LEVEL_NAMES[state["trust_level"]]
    state["metrics"]["demotions"] = state["metrics"].get("demotions", 0) + 1
    state["metrics"]["consecutive_failures"] = 0
    state["promoted_at"] = datetime.now(timezone.utc).isoformat()
    state["history"].append({
        "level": state["trust_level"],
        "date": datetime.now(timezone.utc).isoformat(),
        "reason": f"demotion:{reason}",
    })
    _save_state(state)
    event_bus.publish(
        "autonomy.demoted", "autonomy_state",
        {"new_level": state["trust_level"], "reason": reason},
    )

def penalize_drive_state(worker_id: str, penalty_factor: float):
    """Phase C Item 20: Directly penalize DriveState for conscience violations.
    Reduces curiosity and increases boredom, reflecting loss of motivation due to misalignment.
    """
    state = _load_state()
    drives = state.get("drives", {"curiosity": 0.5, "boredom": 0.0, "last_updated": datetime.now(timezone.utc).isoformat()})

    # Reduce curiosity, increase boredom
    drives["curiosity"] = max(0.0, drives["curiosity"] - penalty_factor)
    drives["boredom"] = min(1.0, drives["boredom"] + penalty_factor * 0.5) # Boredom increases slower than curiosity drops

    drives["last_updated"] = datetime.now(timezone.utc).isoformat()
    state["drives"] = drives
    _save_state(state)
    event_bus.publish(
        "autonomy.drive_penalized", "autonomy_state",
        {"worker_id": worker_id, "penalty_factor": penalty_factor, "new_curiosity": drives["curiosity"], "new_boredom": drives["boredom"]},
    )
    # Removed the log.info for brevity and to avoid excessive output in the main response.

def update_drives(is_idle: bool):
    """Update curiosity and boredom drives. Push exploration tasks if idle."""
    state = _load_state()
    drives = state.get("drives", {
        "curiosity": 0.5, 
        "boredom": 0.0, 
        "last_updated": datetime.now(timezone.utc).isoformat()
    })
    
    try:
        last_update = datetime.fromisoformat(drives["last_updated"].replace("Z", "+00:00"))
    except ValueError:
        last_update = datetime.now(timezone.utc)
        
    now = datetime.now(timezone.utc)
    delta_seconds = (now - last_update).total_seconds()
    
    # Throttle updates to avoid disk thrashing
    if delta_seconds < 60:
        return
        
    # +0.5 boredom per hour if idle, -0.2 if busy
    if is_idle:
        drives["boredom"] = min(1.0, drives["boredom"] + (delta_seconds / 3600.0) * 0.5)
        drives["curiosity"] = min(1.0, drives["curiosity"] + (delta_seconds / 3600.0) * 0.2)
    else:
        drives["boredom"] = max(0.0, drives["boredom"] - 0.2)
        drives["curiosity"] = max(0.0, drives["curiosity"] - 0.1)
        
    drives["last_updated"] = now.isoformat()
    state["drives"] = drives
    
    if is_idle and drives["boredom"] > 0.8:
        _push_exploration_task(drives["curiosity"])
        drives["boredom"] = 0.0  # Reset after pushing
        
    _save_state(state)

def _push_exploration_task(curiosity: float):
    from pulse.core.brain_utils import TASK_BOARD_FILE
    from pulse.core.brain_io import atomic_update_json
    import uuid
    
    def _add_task(data):
        if not isinstance(data, dict):
            data = {"dispatches": []}
            
        focus = "architecture" if curiosity > 0.7 else "refactoring"
        task_id = f"explore_{uuid.uuid4().hex[:8]}"
        
        task = {
            "task_id": task_id,
            "id": task_id,
            "title": f"[EXPLORATION] Autonomous {focus} scan",
            "description": f"Agent idle. Curiosity drive at {curiosity:.2f}. Perform a proactive codebase scan for {focus} improvements.",
            "domain": focus,
            "complexity": "medium",
            "recommended_tier": "standard",
            "status": "open",
            "claimed_by": None,
            "outcome": None
        }
        
        dispatch = {
            "dispatch_id": f"d_{task_id}",
            "prompt": "Autonomous DriveState Trigger",
            "dispatched_at": datetime.now(timezone.utc).isoformat(),
            "tasks": [task]
        }
        
        data.setdefault("dispatches", []).append(dispatch)
        return data

    try:
        atomic_update_json(TASK_BOARD_FILE, _add_task, default={"dispatches": []})
    except Exception:
        pass
