#!/usr/bin/env python3
"""Emit the unexecuted least-privilege GCP staging packet for Observatory."""

from __future__ import annotations

import argparse
import json
import shlex

PROJECT = "teleo-501523"
PROJECT_NUMBER = "785938879453"
REGION = "europe-west6"
GITHUB_REPOSITORY = "living-ip/teleo-infrastructure"
WIF_POOL = "github-actions"
DEPLOY_WIF_PROVIDER = "observatory-read-adapter-main"
DEPLOY_WIF_PROVIDER_RESOURCE = (
    f"projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/{WIF_POOL}/providers/{DEPLOY_WIF_PROVIDER}"
)
DEPLOY_WORKFLOW_REF = (
    f"{GITHUB_REPOSITORY}/.github/workflows/gcp-observatory-read-adapter.yml@refs/heads/main"
)
DEPLOY_WIF_ATTRIBUTE_MAPPING = (
    "google.subject=assertion.sub,attribute.repository=assertion.repository,"
    "attribute.ref=assertion.ref,attribute.workflow_ref=assertion.workflow_ref,"
    "attribute.observatory_workflow=assertion.workflow_ref"
)
DEPLOY_WIF_ATTRIBUTE_CONDITION = (
    "assertion.repository=='living-ip/teleo-infrastructure' && "
    "assertion.ref=='refs/heads/main' && "
    f"assertion.workflow_ref=='{DEPLOY_WORKFLOW_REF}'"
)
BUILD_SERVICE_ACCOUNT = f"sa-artifact-builder@{PROJECT}.iam.gserviceaccount.com"
DEPLOY_SERVICE_ACCOUNT_ID = "sa-observatory-deployer"
DEPLOY_SERVICE_ACCOUNT = f"{DEPLOY_SERVICE_ACCOUNT_ID}@{PROJECT}.iam.gserviceaccount.com"
RUNTIME_SERVICE_ACCOUNT_ID = "sa-observatory-read-adapter"
RUNTIME_SERVICE_ACCOUNT = f"{RUNTIME_SERVICE_ACCOUNT_ID}@{PROJECT}.iam.gserviceaccount.com"
DB_IAM_USER = f"{RUNTIME_SERVICE_ACCOUNT_ID}@{PROJECT}.iam"
SERVICE = "observatory-read-adapter-staging"
INSTANCE = "teleo-pgvector-standby"
NETWORK = "teleo-staging-net"
SUBNET = "teleo-staging-europe-west6"
SECRET = "observatory-read-api-key-staging"
REPOSITORY = "teleo"
PREFLIGHT_ROLE_ID = "observatoryStagingPreflight"
PREFLIGHT_ROLE = f"projects/{PROJECT}/roles/{PREFLIGHT_ROLE_ID}"
DEPLOY_ROLE_ID = "observatoryStagingDeployer"
DEPLOY_ROLE = f"projects/{PROJECT}/roles/{DEPLOY_ROLE_ID}"
PREFLIGHT_PERMISSIONS = (
    "artifactregistry.repositories.getIamPolicy",
    "cloudsql.instances.get",
    "cloudsql.users.list",
    "compute.networks.get",
    "compute.subnetworks.get",
    "iam.serviceAccounts.get",
    "iam.serviceAccounts.getIamPolicy",
    "iam.roles.get",
    "iam.workloadIdentityPoolProviders.get",
    "iam.workloadIdentityPoolProviders.list",
    "resourcemanager.projects.get",
    "resourcemanager.projects.getIamPolicy",
    "run.operations.get",
    "run.services.get",
    "run.services.getIamPolicy",
    "secretmanager.secrets.getIamPolicy",
    "serviceusage.services.get",
    "serviceusage.services.use",
)
DEPLOY_PERMISSIONS = (
    "run.operations.get",
    "run.services.create",
    "run.services.get",
    "run.services.setIamPolicy",
    "run.services.update",
)
REQUIRED_APIS = (
    "artifactregistry.googleapis.com",
    "compute.googleapis.com",
    "iamcredentials.googleapis.com",
    "run.googleapis.com",
    "secretmanager.googleapis.com",
    "sqladmin.googleapis.com",
    "sts.googleapis.com",
)
FORBIDDEN_DEPLOYER_ROLES = (
    "roles/artifactregistry.writer",
    "roles/cloudsql.admin",
    "roles/compute.admin",
    "roles/editor",
    "roles/owner",
    "roles/run.admin",
    "roles/run.developer",
    "roles/secretmanager.admin",
)


def shell_join(parts: list[str]) -> str:
    return " ".join(shlex.quote(part) for part in parts)


def github_wif_member() -> str:
    return (
        f"principalSet://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/"
        f"workloadIdentityPools/{WIF_POOL}/attribute.observatory_workflow/{DEPLOY_WORKFLOW_REF}"
    )


def legacy_pool_wide_github_wif_member() -> str:
    return (
        f"principal://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/"
        f"workloadIdentityPools/{WIF_POOL}/subject/repo:{GITHUB_REPOSITORY}:ref:refs/heads/main"
    )


def service_account_member(account: str) -> str:
    return f"serviceAccount:{account}"


def project_binding(member: str, role: str, condition: str | None = None) -> str:
    command = [
        "gcloud",
        "projects",
        "add-iam-policy-binding",
        PROJECT,
        "--member",
        member,
        "--role",
        role,
    ]
    if condition:
        command.extend(["--condition", condition])
    return shell_join(command)


def custom_role_commands(
    role_id: str,
    title: str,
    description: str,
    permissions: tuple[str, ...],
) -> list[str]:
    common = [
        "--project",
        PROJECT,
        "--title",
        title,
        "--description",
        description,
        "--permissions",
        ",".join(permissions),
        "--stage",
        "GA",
    ]
    return [
        (
            f"gcloud iam roles describe {shlex.quote(role_id)} --project {shlex.quote(PROJECT)} "
            "|| "
            + shell_join(["gcloud", "iam", "roles", "create", role_id, *common])
        ),
        shell_join(["gcloud", "iam", "roles", "update", role_id, *common]),
    ]


def build_plan() -> dict[str, object]:
    deployer_member = service_account_member(DEPLOY_SERVICE_ACCOUNT)
    runtime_member = service_account_member(RUNTIME_SERVICE_ACCOUNT)
    cloud_sql_condition = (
        "expression=resource.name == "
        f"'projects/{PROJECT}/instances/{INSTANCE}' && resource.service == 'sqladmin.googleapis.com',"
        "title=observatory-exact-cloudsql-instance"
    )
    create_accounts = [
        (
            DEPLOY_SERVICE_ACCOUNT,
            DEPLOY_SERVICE_ACCOUNT_ID,
            "Observatory staging deploy and canary",
        ),
        (
            RUNTIME_SERVICE_ACCOUNT,
            RUNTIME_SERVICE_ACCOUNT_ID,
            "Observatory private Cloud SQL reader",
        ),
    ]
    commands = [
        shell_join(["gcloud", "projects", "describe", PROJECT, "--format=value(projectId)"]),
        shell_join(["gcloud", "services", "enable", *REQUIRED_APIS, "--project", PROJECT]),
        project_binding(
            f"serviceAccount:service-{PROJECT_NUMBER}@serverless-robot-prod.iam.gserviceaccount.com",
            "roles/run.serviceAgent",
        ),
    ]
    for email, account_id, display_name in create_accounts:
        commands.append(
            f"gcloud iam service-accounts describe {shlex.quote(email)} --project {shlex.quote(PROJECT)} "
            f"|| {shell_join(['gcloud', 'iam', 'service-accounts', 'create', account_id, '--project', PROJECT, '--display-name', display_name])}"
        )
    commands.extend(
        [
            (
                "gcloud iam workload-identity-pools providers describe "
                + shlex.quote(DEPLOY_WIF_PROVIDER)
                + " --project "
                + shlex.quote(PROJECT)
                + " --location global --workload-identity-pool "
                + shlex.quote(WIF_POOL)
                + " || "
                + shell_join(
                    [
                        "gcloud",
                        "iam",
                        "workload-identity-pools",
                        "providers",
                        "create-oidc",
                        DEPLOY_WIF_PROVIDER,
                        "--project",
                        PROJECT,
                        "--location",
                        "global",
                        "--workload-identity-pool",
                        WIF_POOL,
                        "--issuer-uri",
                        "https://token.actions.githubusercontent.com/",
                        "--attribute-mapping",
                        DEPLOY_WIF_ATTRIBUTE_MAPPING,
                        "--attribute-condition",
                        DEPLOY_WIF_ATTRIBUTE_CONDITION,
                    ]
                )
            ),
            shell_join(
                [
                    "gcloud",
                    "iam",
                    "workload-identity-pools",
                    "providers",
                    "update-oidc",
                    DEPLOY_WIF_PROVIDER,
                    "--project",
                    PROJECT,
                    "--location",
                    "global",
                    "--workload-identity-pool",
                    WIF_POOL,
                    "--attribute-mapping",
                    DEPLOY_WIF_ATTRIBUTE_MAPPING,
                    "--attribute-condition",
                    DEPLOY_WIF_ATTRIBUTE_CONDITION,
                ]
            ),
            shell_join(
                [
                    "gcloud",
                    "iam",
                    "service-accounts",
                    "add-iam-policy-binding",
                    DEPLOY_SERVICE_ACCOUNT,
                    "--project",
                    PROJECT,
                    "--member",
                    github_wif_member(),
                    "--role",
                    "roles/iam.workloadIdentityUser",
                ]
            ),
        ]
    )
    commands.extend(
        custom_role_commands(
            PREFLIGHT_ROLE_ID,
            "Observatory staging preflight",
            "Read only the exact resource classes required before the private staging deploy",
            PREFLIGHT_PERMISSIONS,
        )
    )
    commands.extend(
        custom_role_commands(
            DEPLOY_ROLE_ID,
            "Observatory staging deployer",
            "Create or update Cloud Run without delete or broad infrastructure permissions",
            DEPLOY_PERMISSIONS,
        )
    )
    commands.extend(
        [
            (
                "DEPLOYER_POLICY_JSON=$(gcloud iam service-accounts get-iam-policy "
                + shlex.quote(DEPLOY_SERVICE_ACCOUNT)
                + " --project "
                + shlex.quote(PROJECT)
                + " --format=json)"
            ),
            (
                "if jq -e --arg legacy "
                + shlex.quote(legacy_pool_wide_github_wif_member())
                + " 'any(.bindings[]?; .role == \"roles/iam.workloadIdentityUser\" "
                "and ((.members // []) | index($legacy)))' <<<\"${DEPLOYER_POLICY_JSON}\" >/dev/null; then "
                + shell_join(
                    [
                        "gcloud",
                        "iam",
                        "service-accounts",
                        "remove-iam-policy-binding",
                        DEPLOY_SERVICE_ACCOUNT,
                        "--project",
                        PROJECT,
                        "--member",
                        legacy_pool_wide_github_wif_member(),
                        "--role",
                        "roles/iam.workloadIdentityUser",
                    ]
                )
                + "; fi"
            ),
            project_binding(deployer_member, PREFLIGHT_ROLE),
            project_binding(deployer_member, DEPLOY_ROLE),
            shell_join(
                [
                    "gcloud",
                    "artifacts",
                    "repositories",
                    "add-iam-policy-binding",
                    REPOSITORY,
                    "--project",
                    PROJECT,
                    "--location",
                    REGION,
                    "--member",
                    deployer_member,
                    "--role",
                    "roles/artifactregistry.reader",
                ]
            ),
            shell_join(
                [
                    "gcloud",
                    "iam",
                    "service-accounts",
                    "add-iam-policy-binding",
                    RUNTIME_SERVICE_ACCOUNT,
                    "--project",
                    PROJECT,
                    "--member",
                    deployer_member,
                    "--role",
                    "roles/iam.serviceAccountUser",
                ]
            ),
            project_binding(runtime_member, "roles/cloudsql.client", cloud_sql_condition),
            project_binding(runtime_member, "roles/cloudsql.instanceUser", cloud_sql_condition),
            f"gcloud secrets describe {shlex.quote(SECRET)} --project {shlex.quote(PROJECT)} "
            f"|| {shell_join(['gcloud', 'secrets', 'create', SECRET, '--project', PROJECT, '--replication-policy', 'automatic'])}",
        ]
    )
    for member in (runtime_member, deployer_member):
        commands.append(
            shell_join(
                [
                    "gcloud",
                    "secrets",
                    "add-iam-policy-binding",
                    SECRET,
                    "--project",
                    PROJECT,
                    "--member",
                    member,
                    "--role",
                    "roles/secretmanager.secretAccessor",
                ]
            )
        )
    commands.extend(
        [
            shell_join(
                [
                    "gcloud",
                    "secrets",
                    "add-iam-policy-binding",
                    SECRET,
                    "--project",
                    PROJECT,
                    "--member",
                    deployer_member,
                    "--role",
                    "roles/secretmanager.viewer",
                ]
            ),
            (
                "if ! gcloud secrets versions list "
                + shlex.quote(SECRET)
                + " --project "
                + shlex.quote(PROJECT)
                + " --filter='state=ENABLED' --limit=1 --format='value(name)' | grep -q .; then "
                + "openssl rand -hex 32 | tr -d '\\n' | gcloud secrets versions add "
                + shlex.quote(SECRET)
                + " --project "
                + shlex.quote(PROJECT)
                + " --data-file=-; fi"
            ),
            (
                "if ! gcloud sql users list --instance "
                + shlex.quote(INSTANCE)
                + " --project "
                + shlex.quote(PROJECT)
                + " --filter='type=CLOUD_IAM_SERVICE_ACCOUNT' --format='value(name)' | grep -Fxq "
                + shlex.quote(DB_IAM_USER)
                + "; then "
                + shell_join(
                    [
                        "gcloud",
                        "sql",
                        "users",
                        "create",
                        DB_IAM_USER,
                        "--instance",
                        INSTANCE,
                        "--project",
                        PROJECT,
                        "--type",
                        "CLOUD_IAM_SERVICE_ACCOUNT",
                    ]
                )
                + "; fi"
            ),
        ]
    )

    return {
        "schema": "livingip.observatory-read-adapter-gcp-plan.v1",
        "project": PROJECT,
        "required_tier": "T3_live_readonly",
        "current_tier": "T2_unexecuted_least_privilege_packet",
        "claim_ceiling": "Plan only; no IAM, API, secret, Cloud SQL, Cloud Run, or routing mutation has run.",
        "identities": {
            "build": BUILD_SERVICE_ACCOUNT,
            "deploy_and_canary": DEPLOY_SERVICE_ACCOUNT,
            "runtime": RUNTIME_SERVICE_ACCOUNT,
            "database_principal": DB_IAM_USER,
        },
        "kept_narrow": {
            "artifact_builder": "image build and push only; never deploy or receive broad infra roles",
            "deployer": "workflow-specific main-only WIF plus a five-permission Cloud Run role, repository read, exact runtime actAs, exact secret access",
            "runtime": "exact Cloud SQL instance connect/login plus exact secret access",
        },
        "github_wif_provider": DEPLOY_WIF_PROVIDER_RESOURCE,
        "github_wif_member": github_wif_member(),
        "legacy_pool_wide_github_wif_member_removed": legacy_pool_wide_github_wif_member(),
        "workflow_authentication": {
            "provider": DEPLOY_WIF_PROVIDER_RESOURCE,
            "service_account": DEPLOY_SERVICE_ACCOUNT,
            "principal_set": github_wif_member(),
            "fallback_provider_allowed": False,
            "required_condition": DEPLOY_WIF_ATTRIBUTE_CONDITION,
        },
        "provider_isolation": {
            "pool": WIF_POOL,
            "dedicated_provider": DEPLOY_WIF_PROVIDER,
            "exclusive_attribute": "attribute.observatory_workflow",
            "all_providers_must_be_enumerated": True,
            "non_dedicated_provider_mapping_allowed": False,
        },
        "required_apis": list(REQUIRED_APIS),
        "preflight_custom_role": {
            "name": PREFLIGHT_ROLE,
            "permissions": list(PREFLIGHT_PERMISSIONS),
        },
        "deploy_custom_role": {
            "name": DEPLOY_ROLE,
            "permissions": list(DEPLOY_PERMISSIONS),
        },
        "conditions": {
            "cloud_sql": cloud_sql_condition,
            "deployer_wif": DEPLOY_WIF_ATTRIBUTE_CONDITION,
        },
        "commands": commands,
        "private_database_action": {
            "location": "existing authenticated private GCP VM database-admin path",
            "command": (
                f"OBSERVATORY_DB_IAM_USER={DB_IAM_USER} psql --dbname=teleo_canonical "
                "--set=ON_ERROR_STOP=1 --file=ops/observatory_read_role.sql"
            ),
            "required_receipt": (
                "database=teleo_canonical, authorization_role=kb_observatory_read, exact database principal, "
                "required_reads=true, effective_table_writes_denied=true"
            ),
        },
        "cloud_run_service_agent_check": {
            "principal": f"service-{PROJECT_NUMBER}@serverless-robot-prod.iam.gserviceaccount.com",
            "required_role": "roles/run.serviceAgent",
            "reason": "Default Cloud Run service-agent role carries Direct VPC permissions; do not grant them to the runtime identity.",
            "empty_readback_action": "Stop. Repair the Google-managed service-agent grant as an administrator before preflight.",
        },
        "post_apply_checks": [
            f"gcloud projects describe {PROJECT} --format=value(projectId)",
            "python3 ops/check_gcp_infra_readiness.py",
            "Require the adapter preflight to enumerate every provider in the pool and prove only the dedicated provider maps attribute.observatory_workflow.",
            "Require the adapter preflight to verify custom roles, IAM bindings, private Cloud SQL, secret, and immutable image.",
            (
                "gh workflow run gcp-observatory-read-adapter.yml --repo "
                f"{GITHUB_REPOSITORY} --ref main -f action=preflight_staging"
            ),
            "Require a passing observatory-read-adapter-preflight artifact before action=deploy_staging.",
        ],
        "forbidden_deployer_roles": list(FORBIDDEN_DEPLOYER_ROLES),
        "forbidden_actions": [
            "grant deploy or infra roles to sa-artifact-builder",
            "authenticate the deploy or canary jobs through the general living-ip-github provider",
            "reuse a pre-existing image tag instead of building the current workflow revision",
            "add a public Cloud SQL address",
            "expose a secret value in Git, logs, or a receipt",
            "add a write route",
            "change Vercel or production routing",
        ],
        "production_repoint_executed": False,
    }


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--format", choices=("json", "shell"), default="json")
    args = parser.parse_args()
    plan = build_plan()
    if args.format == "shell":
        print("# Unexecuted staging packet. Review and run only as an authenticated teleo-501523 administrator.")
        print("set -euo pipefail")
        for command in plan["commands"]:
            print(command)
    else:
        print(json.dumps(plan, indent=2, sort_keys=True))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
