"""Phase 5A: Goal Generation Engine — self-directed investigation from brain gaps."""
import json
import uuid
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

GOAL_QUEUE = get_state_dir() / "goal_queue.json"
MAX_DAILY_GOALS = 3


def _load_goals() -> dict:
    if not GOAL_QUEUE.exists():
        return {"goals": []}
    try:
        return json.loads(GOAL_QUEUE.read_text(encoding="utf-8"))
    except Exception:
        return {"goals": []}


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


def formulate_goals(verbose=False) -> dict:
    """
    Main entry point. Called by consolidation daemon.

    Reads:
    - metamemory (domain confidence maps) for blind spots (competence_level == "blind_spot")
    - prediction metrics for accuracy drops
    - brain health alerts
    - interoception alerts

    Creates goals with types: investigation, improvement, maintenance, learning, creative
    Each goal has trust_level_required (0-4), defaults to 0 (needs human approval at Level 0).

    Budget: Max 3 goals per day.

    Returns: {"goals_created": int, "goals": [...]}
    """
    now = datetime.now(timezone.utc)
    data = _load_goals()

    # Count today's goals
    today = now.strftime("%Y-%m-%d")
    today_count = sum(1 for g in data["goals"] if g.get("created_at", "").startswith(today))
    if today_count >= MAX_DAILY_GOALS:
        if verbose:
            print(f"  [GOALS] Budget exhausted ({today_count}/{MAX_DAILY_GOALS} today)")
        return {"goals_created": 0, "goals": []}

    new_goals = []
    remaining = MAX_DAILY_GOALS - today_count

    # Source 1: Metamemory blind spots
    try:
        from pulse.brain.metacognition.metamemory import get_metamemory
        confidence_map = get_metamemory()
        for domain, info in confidence_map.items():
            if remaining <= 0:
                break
            if info.get("competence_level") == "blind_spot":
                goal = _create_goal(
                    type="investigation",
                    title=f"Investigate blind spot: {domain}",
                    description=(
                        f"Domain '{domain}' has Wilson lower bound "
                        f"{info.get('wilson_lower', 0):.2f}. Need more knowledge."
                    ),
                    triggers=["metamemory_blind_spot"],
                    trust_level_required=1,
                )
                new_goals.append(goal)
                remaining -= 1
    except Exception:
        pass

    # Source 2: Interoception alerts
    try:
        from pulse.core.interoception import get_alerts
        alerts = get_alerts()
        for alert in alerts[:remaining]:
            goal = _create_goal(
                type="maintenance",
                title=f"Fix: {alert.get('signal', 'unknown')} alert",
                description=(
                    f"Signal '{alert.get('signal')}' exceeded threshold: "
                    f"{alert.get('value', 0):.2f} > {alert.get('threshold', 0):.2f}"
                ),
                triggers=["interoception_alert"],
                trust_level_required=0,
            )
            new_goals.append(goal)
            remaining -= 1
            if remaining <= 0:
                break
    except Exception:
        pass

    # Source 3: Prediction accuracy drop
    try:
        pred_metrics = get_state_dir() / "prediction_metrics.json"
        if pred_metrics.exists():
            metrics = json.loads(pred_metrics.read_text(encoding="utf-8"))
            accuracy = metrics.get("accuracy", 1.0)
            if accuracy < 0.5 and remaining > 0:
                goal = _create_goal(
                    type="improvement",
                    title="Improve prediction accuracy",
                    description=f"Oracle accuracy dropped to {accuracy:.2f}. Review prediction pipeline.",
                    triggers=["prediction_accuracy_drop"],
                    trust_level_required=2,
                )
                new_goals.append(goal)
                remaining -= 1
    except Exception:
        pass

    # Save new goals
    if new_goals:
        data["goals"].extend(new_goals)
        _save_goals(data)
        for g in new_goals:
            event_bus.publish(
                "goal.created", "goal_engine",
                {"goal_id": g["id"], "type": g["type"], "title": g["title"]},
            )
        if verbose:
            print(f"  [GOALS] Created {len(new_goals)} goals")

    return {"goals_created": len(new_goals), "goals": new_goals}


def _create_goal(
    type: str,
    title: str,
    description: str,
    triggers: list,
    trust_level_required: int = 0,
) -> dict:
    return {
        "id": f"goal_{uuid.uuid4().hex[:8]}",
        "type": type,
        "title": title,
        "description": description,
        "triggers": triggers,
        "trust_level_required": trust_level_required,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "status": "proposed",
        "human_approval": False,
        "decomposed_tasks": [],
    }


def get_pending_goals() -> list:
    """Return goals needing human approval."""
    data = _load_goals()
    return [g for g in data["goals"] if g["status"] == "proposed"]


def approve_goal(goal_id: str) -> bool:
    """Human approves a goal. Returns True if found and approved."""
    data = _load_goals()
    for g in data["goals"]:
        if g["id"] == goal_id:
            g["status"] = "approved"
            g["human_approval"] = True
            _save_goals(data)
            event_bus.publish("goal.approved", "goal_engine", {"goal_id": goal_id})
            return True
    return False
