"""CIS-style asynchronous tasks shared by REST and SOAP."""

from __future__ import annotations

import json
import secrets
from datetime import UTC, datetime
from typing import Any

from app.db.pool import Database


def _pool(database: Database) -> Any:
    return database.pool  # type: ignore[attr-defined]


async def create_task(
    database: Database,
    *,
    description: str,
    service: str,
    operation: str,
    status: str = "SUCCEEDED",
    result: dict[str, Any] | None = None,
    error: dict[str, Any] | None = None,
    task_id: str | None = None,
) -> str:
    resolved_id = task_id or f"task-{secrets.token_hex(8)}"
    now = datetime.now(UTC)
    completed = now if status in {"SUCCEEDED", "FAILED"} else None
    pool = _pool(database)
    async with pool.acquire() as conn:
        await conn.execute(
            """
            INSERT INTO vsphere_tasks
              (id, description, status, service, operation, result, error, completed_at)
            VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7::jsonb, $8)
            ON CONFLICT (id) DO UPDATE SET
              description = EXCLUDED.description,
              status = EXCLUDED.status,
              service = EXCLUDED.service,
              operation = EXCLUDED.operation,
              result = EXCLUDED.result,
              error = EXCLUDED.error,
              completed_at = EXCLUDED.completed_at
            """,
            resolved_id,
            description,
            status,
            service,
            operation,
            json.dumps(result) if result is not None else None,
            json.dumps(error) if error is not None else None,
            completed,
        )
    return resolved_id


async def get_task(database: Database, task_id: str) -> dict[str, Any] | None:
    pool = _pool(database)
    async with pool.acquire() as conn:
        row = await conn.fetchrow("SELECT * FROM vsphere_tasks WHERE id = $1", task_id)
    if row is None:
        return None
    return _row(row)


async def list_tasks(database: Database) -> list[dict[str, Any]]:
    pool = _pool(database)
    async with pool.acquire() as conn:
        rows = await conn.fetch("SELECT * FROM vsphere_tasks ORDER BY created_at DESC LIMIT 200")
    return [_row(row) for row in rows]


def _localizable(message: str, *, message_id: str = "com.vmware.cis.task.description") -> dict[str, Any]:
    return {
        "id": message_id,
        "default_message": message,
        "args": [],
        "localized": message,
    }


def _row(row: Any) -> dict[str, Any]:
    result = row["result"]
    error = row["error"]
    if isinstance(result, str):
        result = json.loads(result)
    if isinstance(error, str):
        error = json.loads(error)
    status = row["status"]
    completed = 100 if status in {"SUCCEEDED", "FAILED"} else 50
    description_text = row["description"] or row["operation"] or "task"
    # Cis Task Info wire shape (Automation) plus lab-friendly aliases used by cookbooks.
    return {
        "task": row["id"],
        "description": _localizable(description_text),
        "status": status,
        "state": status,
        "service": row["service"],
        "operation": row["operation"],
        "cancelable": False,
        "progress": {
            "total": 100,
            "completed": completed,
            "message": _localizable(
                f"{completed}%",
                message_id="com.vmware.cis.task.progress",
            ),
        },
        "result": result,
        "error": error,
        "start_time": row["created_at"].isoformat() if row["created_at"] else None,
        "end_time": row["completed_at"].isoformat() if row["completed_at"] else None,
        "created_at": row["created_at"].isoformat() if row["created_at"] else None,
        "completed_at": row["completed_at"].isoformat() if row["completed_at"] else None,
    }
