"""Cloud client for the publish pipeline: ships the bundle to the host and takes
it back down. Reads the bearer directly (publish works for any signed-in account,
not just pro/free-trial), matching the cloud's requireAuthedUser gate."""
from __future__ import annotations

import httpx

from backend.apps.outputs.publish_common import PublishError
from backend.apps.settings.credentials import account_auth


def p_safe_detail(resp: httpx.Response, fallback: str) -> str:
    try:
        body = resp.json()
        msg = body.get("message") or body.get("error")
        if isinstance(msg, str) and msg:
            return msg
    except Exception:
        pass
    return fallback


async def upload_to_cloud(
    settings, *, output_id: str, name: str, slug_hint: str, bundle: bytes, override: bool
) -> dict:
    token, base = account_auth(settings)
    if not token:
        raise PublishError("Sign in to your OpenSwarm account to publish apps.")
    try:
        async with httpx.AsyncClient(timeout=120.0) as client:
            r = await client.post(
                f"{base}/api/apps/publish",
                headers={"Authorization": f"Bearer {token}"},
                # output_id lets the cloud reuse this app's slug on republish instead of minting a duplicate; override marks a publish past a non-clean scan.
                data={"name": name, "slug": slug_hint, "output_id": output_id, "override": "1" if override else "0"},
                files={"bundle": ("app.tar.gz", bundle, "application/gzip")},
            )
    except httpx.HTTPError:
        raise PublishError("Couldn't reach the publishing service. Check your connection and try again.")
    if r.status_code >= 400:
        raise PublishError(p_safe_detail(r, "Publishing failed. Please try again."))
    return r.json()


async def unpublish_from_cloud(settings, slug: str) -> None:
    token, base = account_auth(settings)
    if not token:
        raise PublishError("Sign in to your OpenSwarm account to manage published apps.")
    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            r = await client.post(
                f"{base}/api/apps/{slug}/delete",
                headers={"Authorization": f"Bearer {token}"},
            )
    except httpx.HTTPError:
        raise PublishError("Couldn't reach the publishing service. Check your connection and try again.")
    if r.status_code >= 400 and r.status_code != 404:
        raise PublishError(p_safe_detail(r, "Couldn't unpublish. Please try again."))
