"""候選審核 queue AI summary persistence writer preflight。

本模組只檢查 metadata_json persistence writer 的 CLI-only 前置條件；
不開 DB connection、不執行 SQL、不讀 approval token、不執行 CLI、不寫檔、
不更新 review_state、不派送 Telegram、不呼叫 LLM、不 commit、不掛 scheduler。
"""


FORBIDDEN_TOKEN_KEYWORDS = (
    "approval_token",
    "approval-token",
    "market_intel_queue_write_approval",
)
SAFE_TOKEN_METADATA_KEYS = {
    "approval_token_present",
    "approval_token_valid",
    "approval_token_secret_configured",
}
APPROVAL_ENV_VAR = "MARKET_INTEL_QUEUE_WRITE_APPROVAL"
TARGET_TABLE = "market_alert_review_queue"
TARGET_COLUMN = "metadata_json"
SUMMARY_METADATA_KEY = "ai_summary_review"
TARGET_OPERATION = "persist_ai_summary_metadata_json"


def _as_dict(value):
    return value if isinstance(value, dict) else {}


def _as_list(value):
    if value is None:
        return []
    if isinstance(value, (list, tuple, set)):
        return list(value)
    return [value]


def _safe_text(value, limit=300):
    if value is None:
        return None
    text = str(value).strip()
    return text[:limit] if text else None


def _contains_forbidden_token_key(value):
    if isinstance(value, dict):
        for key, nested in value.items():
            normalized_key = str(key).lower()
            if normalized_key in SAFE_TOKEN_METADATA_KEYS and isinstance(nested, bool):
                continue
            if normalized_key == "approval_env_var" and nested == APPROVAL_ENV_VAR:
                continue
            if any(token_key in normalized_key for token_key in FORBIDDEN_TOKEN_KEYWORDS):
                return True
            if _contains_forbidden_token_key(nested):
                return True
    elif isinstance(value, list):
        return any(_contains_forbidden_token_key(item) for item in value)
    return False


def _side_effects_clear(*payloads):
    blocked_keys = (
        "ready_for_api_database_write",
        "ready_for_telegram_dispatch",
        "ready_for_scheduler_attach",
        "api_executes_cli",
        "api_executes_llm",
        "api_reads_approval_token",
        "api_writes_file",
        "api_writes_database",
        "api_updates_review_state",
        "summary_persistence_writer_preflight_file_written",
        "writer_preflight_file_written",
        "summary_persistence_transaction_file_written",
        "summary_file_written",
        "summary_record_written",
        "summary_persistence_record_written",
        "metadata_patch_written",
        "transaction_file_written",
        "database_connection_opened",
        "database_session_created",
        "explicit_transaction_opened",
        "transaction_opened",
        "transaction_committed",
        "database_write_executed",
        "database_commit_executed",
        "review_state_update_executed",
        "llm_call_executed",
        "ollama_call_executed",
        "gemini_call_executed",
        "telegram_dispatched",
        "external_network_executed",
        "scheduler_attached",
        "writes_executed",
        "would_write_database",
    )
    return all(
        not _as_dict(payload).get(key)
        for payload in payloads
        for key in blocked_keys
    )


def _operator_summary(operator_evidence):
    operator_evidence = _as_dict(operator_evidence)
    return {
        "provided_keys": sorted(operator_evidence.keys()),
        "operator_confirmed_ai_summary_persistence_writer_preflight": bool(
            operator_evidence.get(
                "operator_confirmed_ai_summary_persistence_writer_preflight"
            )
            or operator_evidence.get("operator_confirmed_summary_persistence_writer_preflight")
        ),
        "operator_confirmed_summary_persistence_is_cli_only": bool(
            operator_evidence.get("operator_confirmed_summary_persistence_is_cli_only")
            or operator_evidence.get("operator_confirmed_persistence_requires_cli")
        ),
        "operator_confirmed_metadata_json_backup_required": bool(
            operator_evidence.get("operator_confirmed_metadata_json_backup_required")
            or operator_evidence.get("operator_confirmed_backup_before_write")
        ),
        "operator_confirmed_postwrite_smoke_required": bool(
            operator_evidence.get("operator_confirmed_postwrite_smoke_required")
            or operator_evidence.get("operator_confirmed_summary_postwrite_smoke_required")
        ),
        "operator_confirmed_no_api_db_write": bool(
            operator_evidence.get("operator_confirmed_no_api_db_write")
        ),
        "operator_confirmed_no_telegram_dispatch": bool(
            operator_evidence.get("operator_confirmed_no_telegram_dispatch")
        ),
        "operator_confirmed_no_scheduler_attach": bool(
            operator_evidence.get("operator_confirmed_no_scheduler_attach")
        ),
        "ai_summary_persistence_transaction_artifact_path": _safe_text(
            operator_evidence.get("ai_summary_persistence_transaction_artifact_path")
            or operator_evidence.get("summary_persistence_transaction_artifact_path")
        ),
        "metadata_json_backup_artifact_path": _safe_text(
            operator_evidence.get("metadata_json_backup_artifact_path")
            or operator_evidence.get("summary_metadata_backup_artifact_path")
        ),
        "postwrite_smoke_plan_path": _safe_text(
            operator_evidence.get("postwrite_smoke_plan_path")
            or operator_evidence.get("summary_persistence_postwrite_smoke_plan_path")
        ),
        "approval_token_submitted_to_api": _contains_forbidden_token_key(
            operator_evidence
        ),
    }


def _statement_payloads(transaction):
    payloads = []
    for statement in _as_list(transaction.get("statements")):
        statement = _as_dict(statement)
        where = _as_dict(statement.get("where"))
        parameters = _as_dict(statement.get("parameter_preview"))
        payloads.append(
            {
                "statement_type": statement.get("statement_type") or "UPDATE",
                "table": statement.get("table"),
                "target_column": statement.get("target_column"),
                "dedupe_key": where.get("dedupe_key") or parameters.get("dedupe_key"),
                "metadata_key": parameters.get("metadata_key"),
                "payload_hash": parameters.get("payload_hash"),
                "execute_in_api": bool(statement.get("execute_in_api")),
                "requires_existing_metadata_merge": bool(
                    statement.get("requires_existing_metadata_merge")
                ),
            }
        )
    return payloads


def _invalid_statements(payloads):
    invalid = []
    for payload in payloads:
        missing_fields = [
            key
            for key in ("table", "target_column", "dedupe_key", "payload_hash")
            if not payload.get(key)
        ]
        invalid_target = bool(
            payload.get("table") != TARGET_TABLE
            or payload.get("target_column") != TARGET_COLUMN
            or payload.get("metadata_key") != SUMMARY_METADATA_KEY
        )
        invalid_execution = bool(payload.get("execute_in_api"))
        if missing_fields or invalid_target or invalid_execution:
            invalid.append(
                {
                    "dedupe_key": payload.get("dedupe_key"),
                    "missing_fields": missing_fields,
                    "target_invalid": invalid_target,
                    "execution_invalid": invalid_execution,
                }
            )
    return invalid


def _transaction_summary(ai_summary_persistence_transaction):
    transaction = _as_dict(ai_summary_persistence_transaction)
    summary = _as_dict(transaction.get("transaction_summary"))
    statement_payloads = _statement_payloads(transaction)
    invalid = _invalid_statements(statement_payloads)
    rollback_plan = _as_list(transaction.get("rollback_plan"))
    return {
        "provided": bool(transaction),
        "mode": transaction.get("mode"),
        "summary_persistence_transaction_ready": bool(
            transaction.get("summary_persistence_transaction_ready")
        ),
        "ready_for_summary_persistence_writer_gate": bool(
            transaction.get("ready_for_summary_persistence_writer_gate")
        ),
        "statement_count": int(transaction.get("statement_count") or 0),
        "summary_payload_hash": transaction.get("summary_payload_hash"),
        "expected_dedupe_keys": _as_list(transaction.get("expected_dedupe_keys")),
        "transaction_summary": summary,
        "statement_payloads": statement_payloads,
        "invalid_statements": invalid,
        "rollback_plan": rollback_plan,
        "blocked_reasons": _as_list(transaction.get("blocked_reasons")),
        "safe_boundaries": _as_list(transaction.get("safe_boundaries")),
        "side_effects_clear": _side_effects_clear(transaction),
    }


def _preflight_gates(*, transaction, operator, apply_real_write):
    summary = transaction["transaction_summary"]
    statements = transaction["statement_payloads"]
    return [
        {
            "key": "summary_persistence_transaction_ready",
            "label": "summary persistence transaction preview 必須已通過",
            "passed": bool(
                transaction["mode"]
                == "candidate_queue_review_ai_summary_persistence_transaction_preview"
                and transaction["summary_persistence_transaction_ready"]
                and transaction["ready_for_summary_persistence_writer_gate"]
            ),
        },
        {
            "key": "summary_persistence_update_statements_valid",
            "label": "UPDATE preview 必須指向 metadata_json.ai_summary_review 且禁止 API 執行",
            "passed": bool(
                statements
                and not transaction["invalid_statements"]
                and len(statements) == transaction["statement_count"]
            ),
        },
        {
            "key": "summary_persistence_cli_contract_ready",
            "label": "transaction summary 必須標示 CLI-only 且 API write disabled",
            "passed": bool(
                summary.get("manual_cli_required")
                and summary.get("api_write_allowed") is False
            ),
        },
        {
            "key": "summary_persistence_rollback_plan_ready",
            "label": "正式寫入前必須有 metadata_json backup 與還原計畫",
            "passed": bool(len(transaction["rollback_plan"]) >= 3),
        },
        {
            "key": "operator_confirmed_summary_persistence_writer_preflight",
            "label": "操作員確認本步只做 CLI writer preflight，不由 API 寫入",
            "passed": bool(
                operator["operator_confirmed_ai_summary_persistence_writer_preflight"]
                and operator["operator_confirmed_summary_persistence_is_cli_only"]
                and operator["operator_confirmed_metadata_json_backup_required"]
                and operator["operator_confirmed_postwrite_smoke_required"]
                and operator["operator_confirmed_no_api_db_write"]
                and operator["operator_confirmed_no_telegram_dispatch"]
                and operator["operator_confirmed_no_scheduler_attach"]
            ),
        },
        {
            "key": "summary_persistence_writer_artifacts_recorded",
            "label": "transaction、metadata backup 與 postwrite smoke plan artifact path 必須齊備",
            "passed": bool(
                operator["ai_summary_persistence_transaction_artifact_path"]
                and operator["metadata_json_backup_artifact_path"]
                and operator["postwrite_smoke_plan_path"]
            ),
        },
        {
            "key": "summary_persistence_writer_preflight_no_approval_token_submitted_to_api",
            "label": "payload 不得包含一次性 approval token key",
            "passed": not operator["approval_token_submitted_to_api"],
        },
        {
            "key": "summary_persistence_writer_preflight_apply_real_write_not_requested_from_api",
            "label": "API/UI preflight 不接受 apply_real_write",
            "passed": not apply_real_write,
        },
        {
            "key": "summary_persistence_writer_preflight_has_no_side_effects",
            "label": "writer preflight 不得開 DB、寫檔、呼叫 LLM、派 Telegram 或掛 scheduler",
            "passed": transaction["side_effects_clear"],
        },
    ]


def build_candidate_queue_review_ai_summary_persistence_writer_preflight(
    *,
    ai_summary_persistence_transaction,
    operator_evidence=None,
    execute_requested=False,
    apply_real_write=False,
):
    """建立 AI summary persistence writer preflight；不執行 SQL 或副作用。"""
    transaction = _transaction_summary(ai_summary_persistence_transaction)
    operator = _operator_summary(operator_evidence)
    gates = _preflight_gates(
        transaction=transaction,
        operator=operator,
        apply_real_write=bool(apply_real_write),
    )
    blocked_reasons = [gate["key"] for gate in gates if not gate["passed"]]
    preflight_ready = bool(not blocked_reasons)

    return {
        "mode": "candidate_queue_review_ai_summary_persistence_writer_preflight_preview",
        "target_table": TARGET_TABLE,
        "target_column": TARGET_COLUMN,
        "target_operation": TARGET_OPERATION,
        "execute_requested": bool(execute_requested),
        "apply_real_write_requested": bool(apply_real_write),
        "summary_persistence_writer_preflight_ready": preflight_ready,
        "ready_for_summary_persistence_run_package": preflight_ready,
        "ready_for_summary_persistence_cli_run": False,
        "ready_for_real_write": False,
        "ready_for_api_database_write": False,
        "ready_for_telegram_dispatch": False,
        "ready_for_scheduler_attach": False,
        "api_executes_cli": False,
        "api_executes_llm": False,
        "api_reads_approval_token": False,
        "api_writes_file": False,
        "api_writes_database": False,
        "api_updates_review_state": False,
        "summary_persistence_writer_preflight_file_written": False,
        "writer_preflight_file_written": False,
        "summary_persistence_transaction_file_written": False,
        "summary_file_written": False,
        "summary_record_written": False,
        "summary_persistence_record_written": False,
        "metadata_patch_written": False,
        "transaction_file_written": False,
        "ai_summary_generated": False,
        "llm_call_executed": False,
        "ollama_call_executed": False,
        "gemini_call_executed": False,
        "telegram_dispatched": False,
        "review_state_update_executed": False,
        "read_only_query_executed": False,
        "database_connection_opened": False,
        "database_session_created": False,
        "explicit_transaction_opened": False,
        "transaction_opened": False,
        "transaction_committed": False,
        "database_write_executed": False,
        "database_commit_executed": False,
        "database_rollback_executed": False,
        "external_network_executed": False,
        "scheduler_attached": False,
        "writes_executed": False,
        "would_write_database": False,
        "statement_count": transaction["statement_count"],
        "invalid_statement_count": len(transaction["invalid_statements"]),
        "statement_payloads": transaction["statement_payloads"],
        "invalid_statements": transaction["invalid_statements"],
        "expected_dedupe_keys": transaction["expected_dedupe_keys"],
        "summary_payload_hash": transaction["summary_payload_hash"],
        "blocked_reasons": blocked_reasons,
        "gates": gates,
        "operator_ai_summary_persistence_writer_preflight": operator,
        "transaction_preview_summary": {
            "mode": transaction["mode"],
            "transaction_ready": transaction["summary_persistence_transaction_ready"],
            "writer_gate_ready": transaction["ready_for_summary_persistence_writer_gate"],
            "statement_count": transaction["statement_count"],
            "manual_cli_required": bool(
                transaction["transaction_summary"].get("manual_cli_required")
            ),
            "api_write_allowed": False,
        },
        "writer_preflight_contract": {
            "target_table": TARGET_TABLE,
            "target_column": TARGET_COLUMN,
            "target_json_path": [SUMMARY_METADATA_KEY],
            "operation": "metadata_json_merge",
            "lookup": "dedupe_key",
            "approval_env_var": APPROVAL_ENV_VAR,
            "manual_cli_required": True,
            "api_write_allowed": False,
            "requires_metadata_json_backup": True,
            "requires_postwrite_smoke": True,
        },
        "next_operator_steps": [
            "保存 transaction preview artifact",
            "CLI 寫入前先備份目標 dedupe_key 的 metadata_json",
            "只在 operator shell 注入一次性 approval token",
            "後續 run package 必須產生 CLI 命令與 payload manifest",
            "正式寫入後立即跑 post-write smoke，且 Telegram dispatch 另開 gate",
        ],
        "safe_boundaries": [
            "do_not_open_database_from_ai_summary_persistence_writer_preflight",
            "do_not_execute_sql_from_ai_summary_persistence_writer_preflight",
            "do_not_write_metadata_json_from_ai_summary_persistence_writer_preflight",
            "do_not_write_summary_writer_preflight_file_from_api",
            "do_not_read_approval_token_from_ai_summary_persistence_writer_preflight",
            "do_not_execute_cli_from_ai_summary_persistence_writer_preflight",
            "do_not_call_llm_from_ai_summary_persistence_writer_preflight",
            "do_not_dispatch_telegram_from_ai_summary_persistence_writer_preflight",
            "do_not_attach_scheduler_from_ai_summary_persistence_writer_preflight",
            "future_summary_persistence_write_must_use_cli_only_gate",
            "metadata_json_backup_required_before_summary_persistence_write",
            "summary_persistence_postwrite_smoke_required",
            "ai_summary_persistence_writer_preflight_preview_only",
            "no_remove_orphans",
            "no_momo_db_lifecycle_change",
        ],
    }
