#!/usr/bin/env python3
"""
IwoooS Public Gateway redacted export 收件預檢產生器。

本工具讀取 Public Gateway live conf 匯出請求包，產生收到 owner-provided
redacted export ref 之前的收件預檢與拒收規則。它不送件、不收 raw conf、
不保存 live conf、不產生 rendered diff、不執行 nginx -t、不 reload、不做
route smoke。
"""

from __future__ import annotations

import argparse
import json
import subprocess
import sys
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any


TAIPEI = timezone(timedelta(hours=8))

INTAKE_FIELDS = [
    "intake_id",
    "export_request_id",
    "config_id",
    "control_tier",
    "redacted_live_conf_ref",
    "ref_owner_role_or_team",
    "received_metadata_ref",
    "sensitive_payload_review",
    "quarantine_ref",
    "rendered_diff_candidate_ref",
    "not_approval",
]

VALIDATION_CHECKS = [
    (
        "source_export_request_snapshot_current",
        "來源匯出請求 snapshot 必須是 committed 最新版本。",
    ),
    (
        "request_sent_metadata_required",
        "沒有可稽核 request sent metadata 時，不得標記 received。",
    ),
    (
        "recipient_confirmed_metadata_required",
        "沒有 owner / recipient role 確認時，不得標記 recipient confirmed。",
    ),
    (
        "redacted_export_ref_required",
        "只接受脫敏 export ref；不得貼 raw live conf 內容。",
    ),
    (
        "raw_live_conf_payload_blocked",
        "若內容含完整 live conf、私鑰、token、cookie、session 或 authorization header，必須拒收或隔離。",
    ),
    (
        "redaction_policy_attestation_required",
        "owner 需聲明已依 redaction policy 處理 upstream credential、secret path 與敏感 payload。",
    ),
    (
        "secret_marker_scan_required",
        "任何可存入 repo 的 metadata 必須先通過 secret marker / sensitive marker 檢查。",
    ),
    (
        "scope_matches_export_request",
        "host、config_id、live path metadata 必須與匯出請求一致；不一致先補件。",
    ),
    (
        "quarantine_before_storage",
        "疑似敏感 payload 只可留下 quarantine metadata，不得寫入 LOGBOOK、前端或 repo artifact。",
    ),
    (
        "rendered_diff_gate_separate",
        "收件通過只代表可進 rendered diff preflight，不授權 nginx -t、reload 或 route smoke。",
    ),
]

REJECTION_GUARDS = [
    "raw_live_conf_payload",
    "tls_private_key",
    "token_secret_cookie_session",
    "authorization_header_or_basic_auth",
    "unredacted_upstream_credential",
    "db_url_or_env_dump",
    "shell_history_or_private_key",
    "unredacted_log_or_screenshot",
    "nginx_test_execution_request",
    "nginx_reload_or_route_change_request",
    "dns_tls_certbot_request",
    "ssh_host_write_or_runtime_request",
]

REVIEWER_INTAKE_LANES = [
    (
        "keep_waiting_redacted_export",
        "尚未送件、尚未確認 recipient 或尚未收到脫敏 export ref 時維持等待。",
        "request_sent / received / accepted / rendered diff / runtime gate 全部維持 0。",
    ),
    (
        "request_more_metadata",
        "缺 owner role、received metadata ref、scope 對應、redaction attestation 或 followup owner 時補件。",
        "不得保存 raw payload，不得增加 accepted。",
    ),
    (
        "quarantine_sensitive_payload",
        "疑似含敏感 payload、raw conf、未脫敏 log 或 credential URL 時隔離。",
        "只可留下 quarantine metadata，不得寫入 repo、LOGBOOK 或前端。",
    ),
    (
        "reject_execution_request",
        "夾帶 nginx -t、reload、route smoke、DNS / TLS、certbot、SSH 或 host write 要求時拒收。",
        "不得轉成 action button 或 runtime approval。",
    ),
    (
        "ready_for_rendered_diff_preflight",
        "欄位完整、只有脫敏 ref、無敏感 payload 且無執行要求時，才可進 rendered diff preflight。",
        "仍不是 rendered diff ready，也不是 nginx / route / runtime 授權。",
    ),
]


def git_short_sha(root: Path) -> str:
    try:
        result = subprocess.run(
            ["git", "rev-parse", "--short", "HEAD"],
            cwd=root,
            check=True,
            capture_output=True,
            text=True,
        )
        return result.stdout.strip()
    except Exception:
        return "unknown"


def load_json(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding="utf-8"))


def validation_checks() -> list[dict[str, Any]]:
    return [
        {
            "check_id": check_id,
            "status": "required_before_redacted_export_intake",
            "required": True,
            "instruction": instruction,
            "gate_effect": "不增加 received / accepted / rendered diff / runtime gate。",
        }
        for check_id, instruction in VALIDATION_CHECKS
    ]


def reviewer_intake_lanes() -> list[dict[str, Any]]:
    return [
        {
            "lane_id": lane_id,
            "status": "redacted_export_intake_lane_defined",
            "instruction": instruction,
            "gate_effect": gate_effect,
        }
        for lane_id, instruction, gate_effect in REVIEWER_INTAKE_LANES
    ]


def intake_candidate_for(export_request: dict[str, Any]) -> dict[str, Any]:
    config_id = export_request["config_id"]
    return {
        "intake_id": f"public_gateway_redacted_export_intake:{config_id}",
        "status": "waiting_redacted_export_ref",
        "export_request_id": export_request["export_request_id"],
        "config_id": config_id,
        "host": export_request["host"],
        "live_path": export_request["live_path"],
        "role": export_request["role"],
        "control_tier": export_request["control_tier"],
        "owner_gate": export_request["owner_gate"],
        "source_snapshot_ref": "docs/security/public-gateway-live-conf-export-request.snapshot.json",
        "redaction_policy_ref": export_request["redaction_policy_ref"],
        "redacted_live_conf_ref": None,
        "ref_owner_role_or_team": "pending_owner_role_or_team",
        "received_metadata_ref": None,
        "sensitive_payload_review": "not_started",
        "quarantine_ref": None,
        "rendered_diff_candidate_ref": None,
        "intake_fields": INTAKE_FIELDS,
        "validation_checks": [check_id for check_id, _instruction in VALIDATION_CHECKS],
        "rejection_guards": REJECTION_GUARDS,
        "reviewer_intake_lanes": [lane_id for lane_id, _instruction, _effect in REVIEWER_INTAKE_LANES],
        "not_approval": True,
        "request_sent": False,
        "recipient_confirmed": False,
        "redacted_export_received": False,
        "accepted_redacted_export": False,
        "quarantine_written": False,
        "rejected_intake": False,
        "raw_live_conf_stored": False,
        "rendered_diff_candidate": False,
        "rendered_diff_authorized": False,
        "nginx_test_authorized": False,
        "nginx_test_executed": False,
        "nginx_reload_authorized": False,
        "route_smoke_authorized": False,
        "route_smoke_executed": False,
        "runtime_gate": False,
        "action_buttons_allowed": False,
        "secret_value_collection_allowed": False,
        "production_write_authorized": False,
    }


def build_report(root: Path, export_request_report: dict[str, Any], generated_at: str | None) -> dict[str, Any]:
    report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds")
    export_requests = export_request_report.get("export_requests", [])
    candidates = [intake_candidate_for(item) for item in export_requests]
    c0_candidates = [item for item in candidates if item.get("control_tier") == "C0"]
    c1_candidates = [item for item in candidates if item.get("control_tier") == "C1"]

    return {
        "schema_version": "public_gateway_redacted_export_intake_preflight_v1",
        "generated_at": report_time,
        "git_commit": git_short_sha(root),
        "source_export_request_schema_version": export_request_report.get("schema_version"),
        "source_export_request_status": export_request_report.get("status"),
        "status": "redacted_export_intake_preflight_ready_no_payload_received",
        "summary": {
            "intake_candidate_count": len(candidates),
            "c0_intake_candidate_count": len(c0_candidates),
            "c1_intake_candidate_count": len(c1_candidates),
            "intake_field_count": len(INTAKE_FIELDS),
            "validation_check_count": len(VALIDATION_CHECKS),
            "rejection_guard_count": len(REJECTION_GUARDS),
            "reviewer_intake_lane_count": len(REVIEWER_INTAKE_LANES),
            "request_sent_count": 0,
            "recipient_confirmed_count": 0,
            "redacted_export_received_count": 0,
            "accepted_redacted_export_count": 0,
            "quarantined_payload_count": 0,
            "rejected_intake_count": 0,
            "rendered_diff_candidate_count": 0,
            "raw_live_conf_stored_count": 0,
            "nginx_test_authorized_count": 0,
            "nginx_test_executed_count": 0,
            "nginx_reload_authorized_count": 0,
            "route_smoke_authorized_count": 0,
            "route_smoke_executed_count": 0,
            "runtime_gate_count": 0,
            "action_button_count": 0,
        },
        "execution_boundaries": {
            "request_sent": False,
            "recipient_confirmed": False,
            "redacted_export_received": False,
            "raw_live_conf_storage_allowed": False,
            "rendered_diff_authorized": False,
            "nginx_test_authorized": False,
            "nginx_test_executed": False,
            "nginx_reload_authorized": False,
            "nginx_reload_executed": False,
            "route_smoke_authorized": False,
            "route_smoke_executed": False,
            "dns_query_executed": False,
            "live_tls_probe_executed": False,
            "certbot_renew_authorized": False,
            "ssh_read_authorized": False,
            "host_live_conf_read_authorized": False,
            "runtime_execution_authorized": False,
            "action_buttons_allowed": False,
            "secret_value_collection_allowed": False,
            "production_write_authorized": False,
            "not_authorization": True,
        },
        "intake_fields": INTAKE_FIELDS,
        "validation_checks": validation_checks(),
        "rejection_guards": REJECTION_GUARDS,
        "reviewer_intake_lanes": reviewer_intake_lanes(),
        "intake_candidates": candidates,
        "next_steps": [
            "只有收到可稽核 request sent metadata 與 owner-provided redacted export ref 後，才能另建收件紀錄。",
            "任何疑似 raw conf 或 sensitive payload 必須先 quarantine，不得寫入 repo、LOGBOOK 或前端。",
            "收件通過後仍只能進 rendered diff preflight；nginx -t、reload、route smoke 需另行人工批准。",
        ],
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="IwoooS Public Gateway redacted export 收件預檢產生器")
    parser.add_argument("--root", default=".", help="repo root")
    parser.add_argument(
        "--export-request-report",
        default="docs/security/public-gateway-live-conf-export-request.snapshot.json",
        help="public-gateway-live-conf-export-request.py 輸出的 JSON",
    )
    parser.add_argument("--output", help="寫出 JSON 報告")
    parser.add_argument("--generated-at", help="固定報告時間，供 committed snapshot 使用")
    args = parser.parse_args()

    root = Path(args.root).resolve()
    export_request_report = load_json(root / args.export_request_report)
    report = build_report(root, export_request_report, args.generated_at)
    payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True)

    if args.output:
        output = Path(args.output)
        output.parent.mkdir(parents=True, exist_ok=True)
        output.write_text(payload + "\n", encoding="utf-8")
    else:
        print(payload)

    summary = report["summary"]
    print(
        "PUBLIC_GATEWAY_REDACTED_EXPORT_INTAKE_PREFLIGHT_OK "
        f"candidates={summary['intake_candidate_count']} "
        f"c0={summary['c0_intake_candidate_count']} "
        f"checks={summary['validation_check_count']} "
        f"rejected={summary['rejected_intake_count']} "
        f"runtime_gate={summary['runtime_gate_count']}",
        file=sys.stderr,
    )
    return 0


if __name__ == "__main__":
    sys.exit(main())
