# Tasks — Starlark Backend (v0.1.0)
#
# Task management extension using ext_data + notifications + triggers.
#
# Entry points:
#   on_request(req)       → surface API routes
#   on_task_event(event)  → event trigger (task.*)
#   on_webhook(req)       → webhook trigger for external task creation
#
# Modules: db, json, notifications, settings


# ═══════════════════════════════════════════════
#  Helpers
# ═══════════════════════════════════════════════

def _resp(status, data):
    return {"status": status, "body": json.encode(data), "headers": {"Content-Type": "application/json"}}

def _str(v):
    if v == None:
        return ""
    return str(v)

def _now():
    """ISO-ish timestamp from Starlark (no time module — use db auto-created_at or pass from caller)."""
    return ""

def _statuses():
    raw = settings.get("statuses")
    if not raw:
        return ["todo", "in_progress", "done", "cancelled"]
    return [s.strip() for s in raw.split(",") if s.strip()]

def _priorities():
    raw = settings.get("priorities")
    if not raw:
        return ["low", "medium", "high", "urgent"]
    return [s.strip() for s in raw.split(",") if s.strip()]


# ═══════════════════════════════════════════════
#  Surface API routes (/s/tasks/api/*)
# ═══════════════════════════════════════════════

def on_request(req):
    path   = req["path"]
    method = req["method"]

    # GET /items — list tasks
    if method == "GET" and path == "/items":
        return _list_items(req)

    # POST /items — create task
    if method == "POST" and path == "/items":
        return _create_item(req)

    # GET /stats — aggregate counts
    if method == "GET" and path == "/stats":
        return _get_stats()

    # GET /items/:id
    if method == "GET" and path.startswith("/items/"):
        return _get_item(path[len("/items/"):])

    # PUT /items/:id
    if method == "PUT" and path.startswith("/items/"):
        return _update_item(path[len("/items/"):], req)

    # DELETE /items/:id
    if method == "DELETE" and path.startswith("/items/"):
        return _delete_item(path[len("/items/"):])

    return _resp(404, {"error": "not found"})


def _list_items(req):
    q = req.get("query", {})
    filters = {}

    status = _str(q.get("status", ""))
    if status:
        filters["status"] = status

    assignee = _str(q.get("assignee_id", ""))
    if assignee:
        filters["assignee_id"] = assignee

    priority = _str(q.get("priority", ""))
    if priority:
        filters["priority"] = priority

    creator = _str(q.get("creator_id", ""))
    if creator:
        filters["creator_id"] = creator

    order = _str(q.get("order", "")) or "created_at"
    limit_str = _str(q.get("limit", ""))
    limit = int(limit_str) if limit_str else 100

    rows = db.query("items", filters=filters, order=order, limit=limit)
    return _resp(200, {"data": rows or []})


def _create_item(req):
    body = json.decode(req.get("body", "{}"))
    user_id = req.get("user_id", "")

    title = _str(body.get("title", ""))
    if not title:
        return _resp(400, {"error": "title is required"})

    statuses = _statuses()
    status = _str(body.get("status", ""))
    if not status:
        status = statuses[0] if statuses else "todo"

    priorities = _priorities()
    priority = _str(body.get("priority", ""))
    if not priority:
        priority = priorities[0] if priorities else "medium"

    row = db.insert("items", {
        "title":       title,
        "description": _str(body.get("description", "")),
        "status":      status,
        "priority":    priority,
        "assignee_id": _str(body.get("assignee_id", "")) or user_id,
        "creator_id":  user_id,
        "due_date":    _str(body.get("due_date", "")),
        "tags":        _str(body.get("tags", "")),
        "updated_at":  "",
        "completed_at":"",
    })
    return _resp(201, row)


def _get_item(item_id):
    rows = db.query("items", filters={"id": item_id}, limit=1)
    if not rows:
        return _resp(404, {"error": "task not found"})
    return _resp(200, rows[0])


def _update_item(item_id, req):
    body = json.decode(req.get("body", "{}"))
    user_id = req.get("user_id", "")

    # Fetch existing to detect transitions
    existing = db.query("items", filters={"id": item_id}, limit=1)
    if not existing:
        return _resp(404, {"error": "task not found"})
    old = existing[0]

    updates = {}
    for key in ["title", "description", "status", "priority", "assignee_id", "due_date", "tags"]:
        if key in body:
            updates[key] = _str(body[key])

    # Detect completion transition
    new_status = updates.get("status", "")
    old_status = _str(old.get("status", ""))
    if new_status == "done" and old_status != "done":
        updates["completed_at"] = "now"  # sentinel — db module handles timestamp

    ok = db.update("items", item_id, updates)
    if not ok:
        return _resp(500, {"error": "update failed"})

    # Notify creator on completion if assignee is different
    if new_status == "done" and old_status != "done":
        creator = _str(old.get("creator_id", ""))
        assignee = _str(old.get("assignee_id", ""))
        if creator and assignee and creator != assignee:
            notifications.send(
                creator,
                "Task completed: " + _str(old.get("title", "")),
                body=_str(old.get("title", "")) + " was marked done by assignee.",
            )

    # Re-fetch updated row
    rows = db.query("items", filters={"id": item_id}, limit=1)
    return _resp(200, rows[0] if rows else {})


def _delete_item(item_id):
    ok = db.delete("items", item_id)
    if not ok:
        return _resp(404, {"error": "task not found"})
    return _resp(200, {"deleted": True})


def _get_stats():
    all_items = db.query("items", limit=10000)
    items = all_items or []
    counts = {}
    for s in _statuses():
        counts[s] = 0
    for item in items:
        st = _str(item.get("status", ""))
        if st in counts:
            counts[st] = counts[st] + 1
        else:
            counts[st] = 1
    return _resp(200, {"counts": counts, "total": len(items)})


# ═══════════════════════════════════════════════
#  Event trigger handler
# ═══════════════════════════════════════════════

def on_task_event(event):
    """Handle task lifecycle events emitted by the platform."""
    label = event.get("event_label", "")
    payload = event.get("event_payload", {})

    if type(payload) == "string":
        payload = json.decode(payload) if payload else {}

    # Could be used for audit logging, metrics, etc.
    # For now just a placeholder — actual notifications happen inline in _update_item.
    pass


# ═══════════════════════════════════════════════
#  Webhook trigger handler
# ═══════════════════════════════════════════════

def on_webhook(req):
    """
    External task creation via webhook.
    POST /api/v1/hooks/tasks/create with JSON body:
      { "title": "...", "description": "...", "priority": "...", "assignee_id": "..." }
    """
    raw_body = req.get("body", "{}")
    body = json.decode(raw_body) if raw_body else {}

    title = _str(body.get("title", ""))
    if not title:
        return {"status": 400, "body": json.encode({"error": "title is required"})}

    priorities = _priorities()
    priority = _str(body.get("priority", ""))
    if not priority:
        priority = priorities[0] if priorities else "medium"

    statuses = _statuses()
    status = statuses[0] if statuses else "todo"

    row = db.insert("items", {
        "title":       title,
        "description": _str(body.get("description", "")),
        "status":      status,
        "priority":    priority,
        "assignee_id": _str(body.get("assignee_id", "")),
        "creator_id":  "",
        "due_date":    _str(body.get("due_date", "")),
        "tags":        _str(body.get("tags", "")),
        "updated_at":  "",
        "completed_at":"",
    })

    return {"status": 201, "body": json.encode(row), "headers": {"Content-Type": "application/json"}}
