"""
Task Board MCP Tools
====================
Shared task board accessible by both Claude and Antigravity agents.
Dual-writes to Redis (real-time) + file snapshot (offline fallback).

Tools:
- task_board_create: Create task in Redis + file snapshot
- task_board_list: List tasks from Redis (file fallback)
- task_board_update: Update task status/priority
- task_board_claim: Claim task ownership (atomic)
- task_board_complete: Mark complete, log result
"""

import json
import sys
import logging
import uuid
from datetime import datetime
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)

# Paths
SYNC_DIR = Path("/mnt/e/genesis-system/data/antigravity-sync")
TASKBOARD_FILE = SYNC_DIR / "taskboard.json"
EVENTS_FILE = SYNC_DIR / "events.jsonl"

# Lazy-loaded components
_task_queue = None
_agent_bus = None


def _get_task_queue():
    """Lazy load TaskQueue."""
    global _task_queue
    if _task_queue is None:
        try:
            sys.path.insert(0, '/mnt/e/genesis-system')
            sys.path.insert(0, '/mnt/e/genesis-system/data/genesis-memory')
            from AIVA.tasks.task_queue import TaskQueue
            _task_queue = TaskQueue()
        except Exception as e:
            logger.warning(f"TaskQueue unavailable: {e}")
    return _task_queue


def _get_agent_bus():
    """Lazy load AgentBus."""
    global _agent_bus
    if _agent_bus is None:
        try:
            sys.path.insert(0, '/mnt/e/genesis-system')
            sys.path.insert(0, '/mnt/e/genesis-system/data/genesis-memory')
            from AIVA.agents.agent_bus import AgentBus
            from AIVA.agents.message_schemas import AgentType
            _agent_bus = AgentBus(agent_type=AgentType.CLAUDE, enable_audit=False)
            _agent_bus.connect()
        except Exception as e:
            logger.warning(f"AgentBus unavailable: {e}")
    return _agent_bus


def _log_event(source: str, event_type: str, data: dict):
    """Append event to events.jsonl."""
    try:
        event = {
            "timestamp": datetime.utcnow().isoformat(),
            "source": source,
            "type": event_type,
            "data": data
        }
        EVENTS_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(EVENTS_FILE, "a") as f:
            f.write(json.dumps(event) + "\n")
    except Exception as e:
        logger.error(f"Failed to log event: {e}")


def _publish_event(event_type: str, payload: dict):
    """Publish event via AgentBus if available."""
    bus = _get_agent_bus()
    if bus:
        try:
            from AIVA.agents.message_schemas import EventMessage, AgentType
            msg = EventMessage(
                sender=AgentType.CLAUDE,
                channel="aiva:events",
                event_type=event_type,
                payload=payload,
                severity="info"
            )
            bus.publish("aiva:events", msg)
        except Exception as e:
            logger.debug(f"Redis event publish failed (file fallback active): {e}")


def _snapshot_board(tasks: list):
    """Write full task board snapshot to file."""
    try:
        snapshot = {
            "tasks": tasks,
            "last_updated": datetime.utcnow().isoformat(),
            "snapshot_source": "task_board_tools"
        }
        TASKBOARD_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(TASKBOARD_FILE, "w") as f:
            json.dump(snapshot, f, indent=2)
    except Exception as e:
        logger.error(f"Failed to snapshot board: {e}")


def _read_board_from_file() -> list:
    """Read task board from file fallback."""
    try:
        if TASKBOARD_FILE.exists():
            with open(TASKBOARD_FILE, "r") as f:
                data = json.load(f)
                return data.get("tasks", [])
    except Exception as e:
        logger.error(f"Failed to read board from file: {e}")
    return []


def _read_board_from_redis() -> Optional[list]:
    """Read all tasks from Redis TaskQueue."""
    queue = _get_task_queue()
    if not queue:
        return None
    try:
        tasks = queue.peek(n=50)
        return [t.to_dict() for t in tasks]
    except Exception as e:
        logger.debug(f"Redis board read failed: {e}")
        return None


def task_board_create(task_json: str) -> str:
    """
    Create a new task on the shared board.

    Args:
        task_json: JSON with fields: title, description, type, urgency (1-10),
                   impact (1-10), deadline (ISO-8601 optional)

    Returns:
        JSON with created task_id and status
    """
    try:
        task_data = json.loads(task_json)
    except json.JSONDecodeError as e:
        return json.dumps({"error": f"Invalid JSON: {e}"})

    task_id = str(uuid.uuid4())
    now = datetime.utcnow().isoformat()

    task_record = {
        "id": task_id,
        "title": task_data.get("title", "Untitled"),
        "description": task_data.get("description", ""),
        "type": task_data.get("type", "general"),
        "urgency": min(10, max(1, task_data.get("urgency", 5))),
        "impact": min(10, max(1, task_data.get("impact", 5))),
        "deadline": task_data.get("deadline"),
        "status": "pending",
        "claimed_by": None,
        "result": None,
        "created_at": now,
        "updated_at": now
    }

    # 1. Write to Redis TaskQueue
    redis_ok = False
    queue = _get_task_queue()
    if queue:
        try:
            from AIVA.tasks.task_schema import Task
            redis_task = Task(
                id=task_id,
                type=task_record["type"],
                urgency=task_record["urgency"],
                impact=task_record["impact"],
                payload={
                    "title": task_record["title"],
                    "description": task_record["description"],
                    "claimed_by": None
                }
            )
            if task_record.get("deadline"):
                redis_task.deadline = datetime.fromisoformat(task_record["deadline"])
            redis_ok = queue.enqueue(redis_task)
        except Exception as e:
            logger.warning(f"Redis enqueue failed: {e}")

    # 2. Publish event via AgentBus
    _publish_event("task_created", {"task_id": task_id, "title": task_record["title"]})

    # 3. Snapshot to file (always)
    existing = _read_board_from_file()
    existing.append(task_record)
    _snapshot_board(existing)

    # 4. Log event
    _log_event("claude", "task_created", {"task_id": task_id, "title": task_record["title"]})

    return json.dumps({
        "task_id": task_id,
        "status": "created",
        "redis": redis_ok,
        "file_snapshot": True
    })


def task_board_list(status: str = "", limit: int = 20) -> str:
    """
    List tasks from the shared board.

    Args:
        status: Filter by status (pending, in_progress, completed, failed). Empty = all.
        limit: Max tasks to return (default 20)

    Returns:
        JSON array of tasks
    """
    # Try Redis first
    tasks = _read_board_from_redis()

    if tasks is None:
        # Fallback to file
        tasks = _read_board_from_file()

    # Filter by status
    if status:
        tasks = [t for t in tasks if t.get("status") == status]

    # Limit
    tasks = tasks[:limit]

    return json.dumps({
        "tasks": tasks,
        "count": len(tasks),
        "source": "redis" if _read_board_from_redis() is not None else "file"
    })


def task_board_update(task_id: str, updates_json: str) -> str:
    """
    Update a task on the shared board.

    Args:
        task_id: ID of task to update
        updates_json: JSON with fields to update (status, priority, description, etc.)

    Returns:
        JSON with update result
    """
    try:
        updates = json.loads(updates_json)
    except json.JSONDecodeError as e:
        return json.dumps({"error": f"Invalid JSON: {e}"})

    now = datetime.utcnow().isoformat()

    # Update in Redis
    redis_ok = False
    queue = _get_task_queue()
    if queue:
        try:
            task = queue.get_task(task_id)
            if task:
                if "urgency" in updates:
                    task.urgency = min(10, max(1, updates["urgency"]))
                if "impact" in updates:
                    task.impact = min(10, max(1, updates["impact"]))
                if "status" in updates:
                    from AIVA.tasks.task_schema import TaskStatus
                    task.status = TaskStatus(updates["status"])
                redis_ok = queue.update_task(task)
        except Exception as e:
            logger.debug(f"Redis update failed: {e}")

    # Update in file
    tasks = _read_board_from_file()
    updated = False
    for t in tasks:
        if t.get("id") == task_id:
            t.update(updates)
            t["updated_at"] = now
            updated = True
            break

    if updated:
        _snapshot_board(tasks)

    # Publish event
    _publish_event("task_updated", {"task_id": task_id, "updates": updates})
    _log_event("claude", "task_updated", {"task_id": task_id, "updates": updates})

    return json.dumps({
        "task_id": task_id,
        "updated": updated or redis_ok,
        "redis": redis_ok,
        "file": updated
    })


def task_board_claim(task_id: str, agent: str) -> str:
    """
    Claim task ownership atomically.

    Args:
        task_id: ID of task to claim
        agent: Agent name claiming the task (e.g., "claude", "antigravity")

    Returns:
        JSON with claim result
    """
    now = datetime.utcnow().isoformat()

    # Atomic claim in Redis via WATCH/MULTI
    redis_claimed = False
    queue = _get_task_queue()
    if queue:
        try:
            task = queue.get_task(task_id)
            if task:
                current_owner = task.payload.get("claimed_by")
                if current_owner and current_owner != agent:
                    return json.dumps({
                        "claimed": False,
                        "error": f"Task already claimed by {current_owner}"
                    })
                task.payload["claimed_by"] = agent
                from AIVA.tasks.task_schema import TaskStatus
                task.status = TaskStatus.IN_PROGRESS
                redis_claimed = queue.update_task(task)
        except Exception as e:
            logger.debug(f"Redis claim failed: {e}")

    # Claim in file
    tasks = _read_board_from_file()
    file_claimed = False
    for t in tasks:
        if t.get("id") == task_id:
            if t.get("claimed_by") and t["claimed_by"] != agent:
                if not redis_claimed:
                    return json.dumps({
                        "claimed": False,
                        "error": f"Task already claimed by {t['claimed_by']}"
                    })
            t["claimed_by"] = agent
            t["status"] = "in_progress"
            t["updated_at"] = now
            file_claimed = True
            break

    if file_claimed:
        _snapshot_board(tasks)

    _publish_event("task_claimed", {"task_id": task_id, "agent": agent})
    _log_event(agent, "task_claimed", {"task_id": task_id})

    return json.dumps({
        "task_id": task_id,
        "claimed": redis_claimed or file_claimed,
        "claimed_by": agent
    })


def task_board_complete(task_id: str, result_json: str) -> str:
    """
    Mark task as complete with result.

    Args:
        task_id: ID of task to complete
        result_json: JSON with result data (summary, files_changed, etc.)

    Returns:
        JSON with completion status
    """
    try:
        result_data = json.loads(result_json)
    except json.JSONDecodeError as e:
        return json.dumps({"error": f"Invalid JSON: {e}"})

    now = datetime.utcnow().isoformat()

    # Complete in Redis
    redis_ok = False
    queue = _get_task_queue()
    if queue:
        try:
            task = queue.get_task(task_id)
            if task:
                from AIVA.tasks.task_schema import TaskStatus
                task.status = TaskStatus.COMPLETED
                task.result = result_data
                redis_ok = queue.update_task(task)
        except Exception as e:
            logger.debug(f"Redis complete failed: {e}")

    # Complete in file
    tasks = _read_board_from_file()
    file_ok = False
    for t in tasks:
        if t.get("id") == task_id:
            t["status"] = "completed"
            t["result"] = result_data
            t["updated_at"] = now
            t["completed_at"] = now
            file_ok = True
            break

    if file_ok:
        _snapshot_board(tasks)

    _publish_event("task_completed", {"task_id": task_id, "result": result_data})
    _log_event("claude", "task_completed", {"task_id": task_id})

    return json.dumps({
        "task_id": task_id,
        "completed": redis_ok or file_ok,
        "redis": redis_ok,
        "file": file_ok
    })
