#!/usr/bin/env python
"""Set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as GitHub org-level secrets.

This is an OPTIONAL alternative to the per-repo secret approach.

By default, P2HS sets these secrets on each repo individually when it creates
the project (using the GitHub App).  Use this script instead if you prefer a
single org-level secret that all repos inherit automatically.

Requires the GitHub App to have ``Organization secrets: Read and write`` org permission
(different from repository-level secrets permission — needs org admin to approve).

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

Reads from .env: GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY (or FILE), GITHUB_INSTALLATION_ID,
GITHUB_ORG, CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID
"""
from __future__ import annotations

import asyncio
import base64
import os
import sys

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


async def main() -> int:
    import httpx
    from nacl import public  # type: ignore[import]

    from src.config import get_settings
    from src.integrations.github_client import GitHubAppClient

    s = get_settings()
    org = (s.github_org or "").strip()
    cf_token = s.cloudflare_api_token.strip()
    cf_account_id = s.cloudflare_account_id.strip()
    installation_id = s.github_installation_id

    missing = [k for k, v in [
        ("GITHUB_ORG", org),
        ("CLOUDFLARE_API_TOKEN", cf_token),
        ("CLOUDFLARE_ACCOUNT_ID", cf_account_id),
        ("GITHUB_INSTALLATION_ID", installation_id),
    ] if not v]
    if missing:
        print(f"ERROR: missing required values: {', '.join(missing)}", file=sys.stderr)
        return 1

    github = GitHubAppClient(installation_id=installation_id)
    token = await github._get_installation_token()  # noqa: SLF001

    headers = {
        "Authorization": f"token {token}",
        "Accept": "application/vnd.github+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }

    secrets_to_set = {
        "CLOUDFLARE_API_TOKEN": cf_token,
        "CLOUDFLARE_ACCOUNT_ID": cf_account_id,
    }

    async with httpx.AsyncClient(timeout=30.0) as client:
        # Get org public key
        key_resp = await client.get(
            f"https://api.github.com/orgs/{org}/actions/secrets/public-key",
            headers=headers,
        )
        if key_resp.status_code == 403:
            print(
                "ERROR: 403 — GitHub App installation token doesn't have org-level\n"
                "'Organization secrets: Read and write' permission.\n\n"
                "Options:\n"
                "  A) Add that permission to your GitHub App → org admin approves\n"
                "     then re-run this script.\n\n"
                "  B) Skip this script entirely — P2HS sets repo-level secrets\n"
                "     automatically per project (already wired into project setup).\n"
                "     No org permission needed for that approach.",
                file=sys.stderr,
            )
            return 1
        key_resp.raise_for_status()
        key_id = key_resp.json()["key_id"]
        public_key_bytes = base64.b64decode(key_resp.json()["key"])

        pk = public.PublicKey(public_key_bytes)
        box = public.SealedBox(pk)

        for name, value in secrets_to_set.items():
            print(f"Setting org secret '{name}' (visibility=all) ...")
            encrypted = base64.b64encode(box.encrypt(value.encode())).decode()
            resp = await client.put(
                f"https://api.github.com/orgs/{org}/actions/secrets/{name}",
                headers=headers,
                json={"encrypted_value": encrypted, "key_id": key_id, "visibility": "all"},
            )
            if resp.status_code not in (201, 204):
                print(f"  ERROR {resp.status_code}: {resp.text}", file=sys.stderr)
                resp.raise_for_status()
            print(f"  {name} set.")

    print("\nDone. All repos in the org now have access to these secrets.")
    return 0


if __name__ == "__main__":
    raise SystemExit(asyncio.run(main()))
