"""Portainer container management deployment playbook.

Defines the steps required to set up Portainer on a tenant server
(ENV_UPDATE + DOCKER_RELOAD). No Playwright setup needed - Portainer's
admin account is created via its first-use web UI which is already
handled during provisioning.

Tenant servers must have stacks and env templates under /opt/letsbe.
"""

import uuid
from typing import Any

from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.task import Task, TaskStatus


class CompositeStep(BaseModel):
    """A single step in a composite playbook."""

    type: str = Field(..., description="Task type (e.g., ENV_UPDATE, DOCKER_RELOAD)")
    payload: dict[str, Any] = Field(
        default_factory=dict, description="Payload for this step"
    )


# LetsBe standard paths
PORTAINER_ENV_PATH = "/opt/letsbe/env/portainer.env"
PORTAINER_STACK_DIR = "/opt/letsbe/stacks/portainer"


def build_portainer_setup_steps(*, domain: str) -> list[CompositeStep]:
    """
    Build the sequence of steps required to set up Portainer.

    Assumes the env file already exists at /opt/letsbe/env/portainer.env
    (created by provisioning/env_setup.sh).

    Args:
        domain: The domain for Portainer (e.g., "portainer.example.com")

    Returns:
        List of 2 CompositeStep objects:
        1. ENV_UPDATE - patches PORTAINER_DOMAIN
        2. DOCKER_RELOAD - restarts the portainer stack with pull=True
    """
    steps = [
        # Step 1: Update environment variables
        CompositeStep(
            type="ENV_UPDATE",
            payload={
                "path": PORTAINER_ENV_PATH,
                "updates": {
                    "PORTAINER_DOMAIN": domain,
                },
            },
        ),
        # Step 2: Reload Docker stack
        CompositeStep(
            type="DOCKER_RELOAD",
            payload={
                "compose_dir": PORTAINER_STACK_DIR,
                "pull": True,
            },
        ),
    ]
    return steps


async def create_portainer_setup_task(
    *,
    db: AsyncSession,
    tenant_id: uuid.UUID,
    agent_id: uuid.UUID | None,
    domain: str,
) -> Task:
    """
    Create and persist a COMPOSITE task for Portainer setup.

    Args:
        db: Async database session
        tenant_id: UUID of the tenant
        agent_id: Optional UUID of the agent to assign the task to
        domain: The domain for Portainer

    Returns:
        The created Task object with type="COMPOSITE"
    """
    steps = build_portainer_setup_steps(domain=domain)

    task = Task(
        tenant_id=tenant_id,
        agent_id=agent_id,
        type="COMPOSITE",
        payload={"steps": [step.model_dump() for step in steps]},
        status=TaskStatus.PENDING.value,
    )

    db.add(task)
    await db.commit()
    await db.refresh(task)

    return task
