"""Inject CLOUD_SERVICE_TOKEN onto every existing generated-app runtime.

Mints a per-project Cloud function token (never INTERNAL_CONTROL_TOKEN), then
pushes it to CF Pages and Cloud env. Idempotent: existing tokens are reused.

Direct Upload Pages projects cannot retry a live deployment; those pick the
secret up on the next wrangler pages deploy.

Usage (P2HS-BE root, same .env as the API):

    python -m scripts.backfill_cloud_service_token
    python -m scripts.backfill_cloud_service_token --dry-run
    python -m scripts.backfill_cloud_service_token --project-id <uuid>
"""
from __future__ import annotations  # noqa: I001

import argparse
import asyncio
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  # noqa: E402
from src.domain.projects.models import MVP_PROJECT_TYPES, Project  # noqa: E402
from src.workers.tasks.env_sync import sync_project_env_vars  # noqa: E402


def _parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Backfill CLOUD_SERVICE_TOKEN onto existing Pages projects.",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="List projects that would be synced; do not mint or push tokens.",
    )
    parser.add_argument(
        "--project-id",
        action="append",
        help="Limit to one Core project UUID (repeatable).",
    )
    return parser.parse_args()


async def _list_projects(project_ids: list[UUID]) -> list[Project]:
    async with async_session_factory() as db:
        stmt = (
            select(Project)
            .where(Project.deleted_at.is_(None))
            .where(Project.type.in_(MVP_PROJECT_TYPES))
            .order_by(Project.created_at.asc())
        )
        if project_ids:
            stmt = stmt.where(Project.id.in_(project_ids))
        return list((await db.execute(stmt)).scalars().all())


async def run(args: argparse.Namespace) -> int:
    ids = [UUID(value) for value in (args.project_id or [])]
    projects = await _list_projects(ids)
    print(f"Found {len(projects)} HTML/React/Nuxt project(s).")
    synced = skipped = errors = 0
    for project in projects:
        ref = project.project_ref or "-"
        print(
            f"  {project.name!r}  ({project.id})  type={project.type}  "
            f"ref={ref}  status={project.status}",
            end=" ",
        )
        if args.dry_run:
            print("[dry-run]")
            skipped += 1
            continue
        try:
            await sync_project_env_vars({}, project_id=str(project.id))
            print("[synced]")
            synced += 1
        except Exception as exc:
            print(f"[ERROR: {exc}]")
            errors += 1
    print(f"\nDone. synced={synced}  dry_run={skipped}  errors={errors}")
    return 1 if errors else 0


def main() -> None:
    raise SystemExit(asyncio.run(run(_parse_args())))


if __name__ == "__main__":
    main()
