#!/usr/bin/env python3
"""Install guarded review/apply prerequisites and ephemeral credentials in a disposable clone."""

from __future__ import annotations

import argparse
import json
import os
import secrets
import subprocess
import sys
from pathlib import Path
from typing import Any

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))

import apply_proposal as ap  # noqa: E402
import run_leo_clone_bound_handler_checkpoint as bound  # noqa: E402


def _psql(
    container: str,
    database: str,
    sql: str,
    *,
    secret_values: tuple[str, ...] = (),
) -> None:
    command = [
        bound.SYSTEM_DOCKER,
        "exec",
        "-i",
        container,
        "psql",
        "-U",
        "postgres",
        "-d",
        database,
        "-v",
        "ON_ERROR_STOP=1",
        "-At",
        "-q",
    ]
    result = subprocess.run(
        command,
        input=sql,
        text=True,
        capture_output=True,
        env={"PATH": bound.SYSTEM_EXEC_PATH},
        check=False,
    )
    if result.returncode != 0:
        raise bound.CheckpointError(
            f"clone gate SQL failed ({result.returncode}): "
            + bound.redact_text(result.stderr or result.stdout, secret_values=secret_values)
        )


def _verify_login(container: str, database: str, role: str, password: str) -> None:
    command = [
        bound.SYSTEM_DOCKER,
        "exec",
        "-e",
        "PGPASSWORD",
        "-i",
        container,
        "psql",
        "-U",
        role,
        "-h",
        "127.0.0.1",
        "-d",
        database,
        "-v",
        "ON_ERROR_STOP=1",
        "-At",
        "-q",
        "-c",
        "select current_user;",
    ]
    result = subprocess.run(
        command,
        text=True,
        capture_output=True,
        env={"PATH": bound.SYSTEM_EXEC_PATH, "PGPASSWORD": password},
        check=False,
    )
    if result.returncode != 0 or result.stdout.strip() != role:
        raise bound.CheckpointError(f"ephemeral {role} clone login verification failed")


def _write_secret(path: Path, key: str, value: str) -> None:
    descriptor = os.open(
        path,
        os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_NOFOLLOW", 0),
        0o600,
    )
    with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
        handle.write(f"{key}={value}\n")
        handle.flush()
        os.fsync(handle.fileno())


def bootstrap(container: str, database: str, output_dir: Path) -> dict[str, Any]:
    target = bound.container_identity(container)
    production = bound.container_identity(bound.PRODUCTION_CONTAINER)
    isolation = bound.validate_disposable_target_identity(target, production)
    target_id = str(target["id"])
    output_dir = output_dir.resolve(strict=True)
    stat = output_dir.stat()
    if not output_dir.is_dir() or stat.st_uid != os.geteuid() or stat.st_mode & 0o077:
        raise bound.CheckpointError("--output-dir must be an existing private directory owned by the current user")
    review_file = output_dir / "kb-review.env"
    apply_file = output_dir / "kb-apply.env"
    if review_file.exists() or review_file.is_symlink() or apply_file.exists() or apply_file.is_symlink():
        raise bound.CheckpointError("clone credential files already exist; use a fresh private run directory")
    review_password = secrets.token_urlsafe(36)
    apply_password = secrets.token_urlsafe(36)
    prereqs = (HERE / "kb_apply_prereqs.sql").read_text(encoding="utf-8")
    _psql(
        target_id,
        database,
        """do $bootstrap$
begin
  if not exists (select 1 from pg_roles where rolname = 'kb_apply') then
    create role kb_apply login;
  end if;
end
$bootstrap$;
""",
    )
    _psql(target_id, database, prereqs)
    _psql(
        target_id,
        database,
        "alter role kb_review password "
        + ap.sql_literal(review_password)
        + ";\nalter role kb_apply password "
        + ap.sql_literal(apply_password)
        + ";\n",
        secret_values=(review_password, apply_password),
    )
    _verify_login(target_id, database, "kb_review", review_password)
    _verify_login(target_id, database, "kb_apply", apply_password)
    manifest = bound._psql_json(
        target_id,
        database,
        """\\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
  'approval_table', to_regclass('kb_stage.kb_proposal_approvals')::text,
  'review_principals_table', to_regclass('kb_stage.kb_review_principals')::text,
  'review_role_exists', exists(select 1 from pg_roles where rolname = 'kb_review'),
  'apply_role_exists', exists(select 1 from pg_roles where rolname = 'kb_apply')
)::text;
rollback;
""",
    )
    if manifest != {
        "approval_table": "kb_stage.kb_proposal_approvals",
        "review_principals_table": "kb_stage.kb_review_principals",
        "review_role_exists": True,
        "apply_role_exists": True,
    }:
        raise bound.CheckpointError("clone gate manifest is incomplete: " + json.dumps(manifest, sort_keys=True))
    _write_secret(review_file, "KB_REVIEW_PASSWORD", review_password)
    try:
        _write_secret(apply_file, "KB_APPLY_DB_PASSWORD", apply_password)
    except BaseException:
        review_file.unlink(missing_ok=True)
        raise
    review_password = ""
    apply_password = ""
    return {
        "status": "ready",
        "bound_container_id": target_id,
        "database": database,
        "isolation_checks": isolation,
        "gate_manifest": manifest,
        "review_secret_file": str(review_file),
        "apply_secret_file": str(apply_file),
        "secret_values_or_hashes_recorded": False,
        "login_roles_verified": ["kb_review", "kb_apply"],
    }


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--container", required=True)
    parser.add_argument("--db", required=True)
    parser.add_argument("--output-dir", required=True, type=Path)
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv)
    try:
        if args.container == bound.PRODUCTION_CONTAINER:
            raise bound.CheckpointError("--container must be a disposable non-production target")
        result = bootstrap(args.container, args.db, args.output_dir)
    except (OSError, bound.CheckpointError) as exc:
        print(json.dumps({"status": "rejected", "error": str(exc)}, sort_keys=True))
        return 2
    print(json.dumps(result, sort_keys=True))
    return 0


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