#!/usr/bin/env python
"""Re-queue ``setup_project_repo`` for projects stuck in ``creating`` (worker down, Redis mismatch, etc.).

The setup pipeline is **idempotent**: partial progress is stored on ``project_repos.setup_stage``,
so re-enqueue is safe even if a ``project_repos`` row already exists.

Usage (from repo root, same ``.env`` as the API):

  python -m scripts.retry_project_setup list
  python -m scripts.retry_project_setup enqueue <project_uuid>
  python -m scripts.retry_project_setup enqueue-all

Requires: ``DATABASE_URL``, ``REDIS_URL`` (must match a **running** worker).
"""
from __future__ import annotations

import argparse
import asyncio
import os
import sys
from uuid import UUID

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


async def _creating_projects():
    from sqlalchemy import select

    from src.core.database import async_session_factory
    from src.domain.projects.models import Project

    async with async_session_factory() as db:
        q = (
            select(Project)
            .where(Project.status == "creating")
            .where(Project.deleted_at.is_(None))
        )
        result = await db.execute(q)
        return list(result.scalars().all())


async def cmd_list() -> int:
    rows = await _creating_projects()
    if not rows:
        print("No projects in status=creating.")
        return 0
    for p in rows:
        print(f"{p.id}\t{p.slug}\t{p.type}\tworkspace={p.workspace_id}\tgithub_repo_name={getattr(p, 'github_repo_name', '')}\tcreated_at={p.created_at}")
    print(f"\nTotal: {len(rows)}")
    return 0


async def cmd_enqueue(project_id: str) -> int:
    from src.core.database import async_session_factory
    from src.domain.projects.repository import ProjectRepository
    from src.workers.enqueue import enqueue_project_setup

    pid = UUID(project_id)
    async with async_session_factory() as db:
        proj = await ProjectRepository(db).get_by_id(pid)
        if not proj:
            print(f"Project not found: {project_id}", file=sys.stderr)
            return 1
        if proj.status != "creating":
            print(f"Refusing: status is {proj.status!r} (expected creating).", file=sys.stderr)
            return 1

    ok = await enqueue_project_setup(str(pid))
    if ok:
        print(f"Enqueued setup_project_repo for {pid}. Worker will resume from last setup_stage if any.")
        return 0
    print("Enqueue returned False — check API logs (arq_enqueue_skipped) and Redis.", file=sys.stderr)
    return 2


async def cmd_enqueue_all() -> int:
    rows = await _creating_projects()
    if not rows:
        print("Nothing to enqueue.")
        return 0
    code = 0
    for p in rows:
        c = await cmd_enqueue(str(p.id))
        if c != 0:
            code = c
    return code


def main() -> None:
    parser = argparse.ArgumentParser(description="Retry project setup jobs for stuck creating projects.")
    sub = parser.add_subparsers(dest="cmd", required=True)

    sub.add_parser("list", help="List projects in status=creating")

    p_enq = sub.add_parser("enqueue", help="Enqueue setup for one project UUID")
    p_enq.add_argument("project_id", help="Project UUID")

    sub.add_parser("enqueue-all", help="Enqueue setup for every creating project (see list)")

    args = parser.parse_args()
    if args.cmd == "list":
        raise SystemExit(asyncio.run(cmd_list()))
    if args.cmd == "enqueue":
        raise SystemExit(asyncio.run(cmd_enqueue(args.project_id)))
    if args.cmd == "enqueue-all":
        raise SystemExit(asyncio.run(cmd_enqueue_all()))
    raise SystemExit(2)


if __name__ == "__main__":
    main()
