from __future__ import annotations

from urllib.parse import quote

import httpx

from app.config import settings


class ManifestClient:
    def fetch_manifest(self, app_id: str, version: str) -> dict:
        app_id_part = quote(app_id, safe="")
        version_part = quote(version, safe="")
        url = f"{settings.robot_package_base_url}/api/apps/{app_id_part}/versions/{version_part}/manifest"
        response = httpx.get(url, follow_redirects=True, timeout=30)
        if response.is_error:
            raise RuntimeError(_format_manifest_error(response))
        return response.json()


def _format_manifest_error(response: httpx.Response) -> str:
    base_message = f"Manifest request failed with HTTP {response.status_code}: {response.url}"

    try:
        payload = response.json()
    except ValueError:
        detail = response.text.strip()
        return f"{base_message}. {detail}" if detail else base_message

    if not isinstance(payload, dict):
        return base_message

    message_parts = []
    error = str(payload.get("error") or "").strip()
    detail = str(payload.get("detail") or "").strip()

    if error:
        message_parts.append(error)
    if detail:
        message_parts.append(detail)

    missing_files = payload.get("missingPackageFiles")
    if isinstance(missing_files, list) and missing_files:
        descriptions = []
        for item in missing_files:
            if not isinstance(item, dict):
                continue

            package_name = str(item.get("packageName") or item.get("componentId") or "package").strip()
            version = str(item.get("version") or "").strip()
            descriptions.append(f"{package_name} {version}".strip())

        if descriptions:
            message_parts.append(f"Missing package files: {', '.join(descriptions)}")

    return f"{base_message}. {' '.join(message_parts)}" if message_parts else base_message
