"""One-time backfill: push all existing workspaces and projects into P2HS Cloud D1.

Iterates every non-deleted workspace, then every non-deleted project within it,
and calls the cloud bootstrap endpoint for each project.  All control endpoints
are idempotent so this is safe to re-run.

Usage (from repo root):
    python -m scripts.backfill_cloud_sync

    # Dry-run (prints what would be sent, no HTTP calls):
    python -m scripts.backfill_cloud_sync --dry-run

    # Single workspace only:
    python -m scripts.backfill_cloud_sync --workspace-id <uuid>

Requirements: DATABASE_URL and CLOUD_* env vars must be set (or .env present).
"""
from __future__ import annotations

import argparse
import asyncio
import sys
from uuid import UUID

from sqlalchemy import select

from src.core.orm_import import import_all_orm_models

import_all_orm_models()

from src.core.database import async_session_factory
from src.domain.projects.models import Project
from src.domain.workspaces.models import Workspace
from src.integrations.cloud_control_client import CloudControlClient


async def bootstrap_project(
    client: CloudControlClient,
    workspace: Workspace,
    project: Project,
    dry_run: bool,
) -> str:
    """Build payloads and call bootstrap. Returns 'synced' | 'dry_run' | 'skipped'."""
    ws_id = str(workspace.id)
    proj_id = str(project.id)
    client_id = f"cli_{project.project_ref or proj_id}"

    workspace_payload = {
        "workspace_id": ws_id,
        "tenant_id": workspace.tenant_ref,
        "name": workspace.name,
        "status": "active" if not workspace.deleted_at else "archived",
        "plan_slug": workspace.selected_plan_slug,
        "cloud_enabled": True,
        "suspended": False,
        "metadata": {},
    }
    project_payload = {
        "project_id": proj_id,
        "workspace_id": ws_id,
        "name": project.name,
        "status": project.status,
        "environment": None,
        "cloud_enabled": True,
        "suspended": False,
        "allowed_request_types": [],
        "origins": [],
        "metadata": {},
    }
    client_payload = {
        "client_id": client_id,
        "workspace_id": ws_id,
        "project_id": proj_id,
        "name": f"{project.name} Client",
        "status": "active",
        "allowed_origins": [],
        "allowed_capabilities": [],
        "handshake_mode": "token",
    }
    capabilities_payload = {
        "project_id": proj_id,
        "version": 1,
        "capabilities": {},
    }

    if dry_run:
        print(f"    [dry-run] would bootstrap project={proj_id} client={client_id}")
        return "dry_run"

    await client.bootstrap_project(
        workspace=workspace_payload,
        project=project_payload,
        clients=[client_payload],
        capabilities=capabilities_payload,
        integrations=[],
    )
    return "synced"


async def run(workspace_id: str | None, dry_run: bool) -> None:
    client = CloudControlClient()
    if not dry_run and not client._is_configured():
        print(
            "ERROR: CLOUD_CONTROL_API_URL and CLOUD_INTERNAL_TOKEN must be set.\n"
            "       Use --dry-run to preview without credentials.",
            file=sys.stderr,
        )
        sys.exit(1)

    synced = skipped = errors = 0

    async with async_session_factory() as db:
        # Load workspaces
        ws_q = select(Workspace).where(Workspace.deleted_at.is_(None))
        if workspace_id:
            ws_q = ws_q.where(Workspace.id == UUID(workspace_id))
        ws_q = ws_q.order_by(Workspace.created_at.asc())
        workspaces = list((await db.execute(ws_q)).scalars().all())

        print(f"Found {len(workspaces)} workspace(s) to process.")

        for ws in workspaces:
            print(f"\nWorkspace: {ws.name!r}  ({ws.id})")

            proj_q = (
                select(Project)
                .where(Project.workspace_id == ws.id)
                .where(Project.deleted_at.is_(None))
                .order_by(Project.created_at.asc())
            )
            projects = list((await db.execute(proj_q)).scalars().all())
            print(f"  {len(projects)} project(s)")

            for project in projects:
                print(f"  -> {project.name!r}  ({project.id})  status={project.status}", end=" ")
                try:
                    result = await bootstrap_project(client, ws, project, dry_run)
                    print(f"[{result}]")
                    if result == "synced":
                        synced += 1
                    elif result == "dry_run":
                        skipped += 1
                except Exception as exc:
                    print(f"[ERROR: {exc}]")
                    errors += 1

    print(f"\nDone. synced={synced}  dry_run={skipped}  errors={errors}")
    if errors:
        sys.exit(1)


def main() -> None:
    parser = argparse.ArgumentParser(description="Backfill existing projects into P2HS Cloud D1.")
    parser.add_argument("--dry-run", action="store_true", help="Print what would be sent without making HTTP calls.")
    parser.add_argument("--workspace-id", metavar="UUID", help="Limit to a single workspace.")
    args = parser.parse_args()
    asyncio.run(run(args.workspace_id, args.dry_run))


if __name__ == "__main__":
    main()
