"""市場情報 MCP fetch candidate queue writer post-closeout inventory review。

本模組只審核 closeout review 之後由 operator shell 完成的 live inventory
read-only 摘要；API/UI 不讀 approval token、不執行 CLI、不開 DB、不寫 queue、
不做 inventory query、不掛 scheduler。
"""

from copy import deepcopy

from services.market_intel.mcp_fetch_candidate_queue_writer_preflight import TARGET_TABLE
from services.market_intel.mcp_fetch_candidate_queue_writer_run_readiness import (
    ARTIFACT_PREFIX,
)
from services.market_intel.mcp_fetch_candidate_queue_writer_run_closeout_review import (
    build_mcp_fetch_candidate_queue_writer_run_closeout_review_preview,
)


_SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE = None

FORBIDDEN_SECRET_KEYS = (
    "approval_token",
    "approval-token",
    "api_key",
    "authorization",
    "bearer",
    "client_secret",
    "cookie",
    "password",
    "secret",
    "session_cookie",
    "token",
)

SAFE_SECRET_METADATA_KEYS = {
    "no_approval_token_payload",
    "operator_confirmed_no_approval_token_payload",
    "token_not_logged",
}

_BLOCKED_SIDE_EFFECT_KEYS = (
    "allow_api_execution",
    "allow_cli_execution",
    "allow_database_write",
    "allow_external_network_in_api",
    "allow_scheduler_attach",
    "api_execution_allowed",
    "api_executed_cli",
    "api_executes",
    "api_executes_cli",
    "api_inventory_query_executed",
    "api_opens_database_connection",
    "api_reads_approval_token",
    "api_uses_external_network",
    "api_writes_database",
    "api_writes_file",
    "apply_real_write",
    "attach_scheduler",
    "candidate_queue_created_by_api",
    "candidate_queue_persisted_by_api",
    "candidate_review_state_updated",
    "cli_executed_by_api",
    "command_executed_by_api",
    "database_commit_executed",
    "database_connection_opened",
    "database_session_created",
    "database_write_executed_by_api",
    "execute_requested",
    "external_network_executed_by_api",
    "file_written",
    "inventory_file_written",
    "inventory_query_executed_by_api",
    "inventory_review_persisted",
    "network_request_allowed",
    "opens_database_connection",
    "package_artifact_created",
    "payload_persisted",
    "post_closeout_inventory_file_written",
    "post_closeout_inventory_persisted",
    "post_closeout_query_executed_by_api",
    "ready_for_api_database_write",
    "ready_for_real_write",
    "real_write_allowed_by_api",
    "review_state_update_executed",
    "scheduler_attach",
    "scheduler_attached",
    "write_database",
    "writes_database",
    "writes_executed",
    "would_write_database",
)


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_int(value):
    try:
        return int(value or 0)
    except (TypeError, ValueError):
        return 0


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


def _safe_path(value, *, prefixes, suffixes):
    if not isinstance(value, str):
        return False
    normalized = value.strip().replace("\\", "/")
    if not normalized or normalized.startswith("/"):
        return False
    parts = [part for part in normalized.split("/") if part]
    if any(part in (".", "..") for part in parts):
        return False
    return normalized.startswith(prefixes) and normalized.endswith(suffixes)


def _contains_forbidden_key(value, forbidden_keys, *, safe_keys=None):
    safe_keys = safe_keys or set()
    if isinstance(value, dict):
        for key, nested in value.items():
            normalized_key = str(key).lower()
            if normalized_key in safe_keys and isinstance(nested, bool):
                continue
            if any(forbidden_key in normalized_key for forbidden_key in forbidden_keys):
                return True
            if _contains_forbidden_key(nested, forbidden_keys, safe_keys=safe_keys):
                return True
    elif isinstance(value, list):
        return any(
            _contains_forbidden_key(item, forbidden_keys, safe_keys=safe_keys)
            for item in value
        )
    return False


def _blocked_side_effects(payload):
    found = []

    def visit(value, path):
        if isinstance(value, dict):
            for key, item in value.items():
                normalized_key = str(key).lower()
                key_path = f"{path}.{key}" if path else key
                if normalized_key in _BLOCKED_SIDE_EFFECT_KEYS and bool(item):
                    found.append(key_path)
                visit(item, key_path)
        elif isinstance(value, list):
            for index, item in enumerate(value):
                visit(item, f"{path}[{index}]")

    visit(payload, "")
    return found


def _closeout_review_from_inputs(closeout_package, closeout_result, phase):
    if isinstance(closeout_result, dict) and closeout_result:
        return closeout_result

    closeout_package = _as_dict(closeout_package)
    return build_mcp_fetch_candidate_queue_writer_run_closeout_review_preview(
        writer_run_receipt_review_package=(
            closeout_package.get("writer_run_receipt_review_package")
            or closeout_package.get("candidate_queue_writer_run_receipt_review")
            or closeout_package.get("writer_run_receipt_review")
            or closeout_package.get("run_receipt_review_package")
            or {}
        ),
        writer_run_receipt_review_result=(
            closeout_package.get("writer_run_receipt_review_result")
            or closeout_package.get(
                "mcp_fetch_candidate_queue_writer_run_receipt_review"
            )
        ),
        operator_closeout=(
            closeout_package.get("operator_closeout")
            or closeout_package.get("writer_run_closeout")
            or closeout_package.get("candidate_queue_writer_run_closeout")
            or closeout_package.get("closeout_payload")
            or closeout_package.get("closeout")
        ),
        phase=phase,
    )


def _sample_post_closeout_inventory_review_package():
    global _SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE
    if _SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE is not None:
        return deepcopy(_SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE)

    closeout_preview = build_mcp_fetch_candidate_queue_writer_run_closeout_review_preview()
    closeout_package = closeout_preview["sample_writer_run_closeout_review_package"]
    closeout_result = (
        build_mcp_fetch_candidate_queue_writer_run_closeout_review_preview(
            writer_run_receipt_review_package=closeout_package[
                "writer_run_receipt_review_package"
            ],
            writer_run_receipt_review_result=closeout_package[
                "writer_run_receipt_review_result"
            ],
            operator_closeout=closeout_package["operator_closeout"],
        )
    )
    closeout = _closeout_review_summary(closeout_result)
    operator_inventory = {
        "inventory_review_id": (
            "market-intel-candidate-writer-post-closeout-inventory-sample"
        ),
        "closeout_id": closeout["closeout_id"],
        "run_package_id": closeout["run_package_id"],
        "receipt_id": closeout["receipt_id"],
        "target_table": TARGET_TABLE,
        "payload_row_count": closeout["payload_row_count"],
        "found_row_count": closeout["payload_row_count"],
        "missing_row_count": 0,
        "unexpected_duplicate_count": 0,
        "inventory_artifact_path": (
            ARTIFACT_PREFIX
            + "candidate-queue-post-closeout-inventory-sample.json"
        ),
        "closeout_review_artifact_path": closeout["closeout_artifact_path"],
        "read_only_query_result_path": (
            ARTIFACT_PREFIX
            + "candidate-queue-post-closeout-read-only-query-sample.json"
        ),
        "query_summary": {
            "query_type": "read_only_select",
            "read_only_query_executed_by_operator": True,
            "expected_rows_found": True,
            "row_count_matches_payload": True,
            "target_table": TARGET_TABLE,
        },
        "operator_confirmations": {
            "closeout_reviewed": True,
            "inventory_read_only": True,
            "no_missing_rows": True,
            "no_unexpected_duplicates": True,
            "no_approval_token_payload": True,
            "no_api_cli_execution": True,
            "no_api_database_write": True,
            "no_api_inventory_query": True,
            "no_api_file_write": True,
            "no_scheduler_attach": True,
        },
        "api_execution_allowed": False,
        "real_write_allowed_by_api": False,
    }
    _SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE = {
        "writer_run_closeout_review_package": closeout_package,
        "writer_run_closeout_review_result": closeout_result,
        "operator_inventory": operator_inventory,
    }
    return deepcopy(_SAMPLE_POST_CLOSEOUT_INVENTORY_REVIEW_PACKAGE)


def _closeout_review_summary(closeout_result):
    closeout_result = _as_dict(closeout_result)
    closeout = _as_dict(closeout_result.get("operator_closeout_summary"))
    side_effects_clear = bool(
        not closeout_result.get("payload_persisted")
        and not closeout_result.get("run_closeout_review_persisted")
        and not closeout_result.get("run_closeout_persisted")
        and not closeout_result.get("run_closeout_file_written")
        and not closeout_result.get("closeout_file_written")
        and not closeout_result.get("package_artifact_created")
        and not closeout_result.get("network_request_allowed")
        and not closeout_result.get("api_executes_cli")
        and not closeout_result.get("api_reads_approval_token")
        and not closeout_result.get("api_opens_database_connection")
        and not closeout_result.get("api_writes_database")
        and not closeout_result.get("api_writes_file")
        and not closeout_result.get("api_uses_external_network")
        and not closeout_result.get("post_closeout_query_executed_by_api")
        and not closeout_result.get("database_write_executed")
        and not closeout_result.get("cli_executed")
        and not closeout_result.get("file_written")
        and not closeout_result.get("scheduler_attached")
        and not closeout_result.get("candidate_queue_created")
        and not closeout_result.get("candidate_queue_persisted")
    )
    return {
        "mode": closeout_result.get("mode"),
        "accepted": bool(
            closeout_result.get(
                "mcp_fetch_candidate_queue_writer_run_closeout_review_accepted"
            )
        ),
        "ready_for_post_closeout_inventory_review": bool(
            closeout_result.get(
                "ready_for_candidate_queue_post_closeout_inventory_review"
            )
        ),
        "closeout_id": _safe_text(closeout.get("closeout_id"), 160),
        "run_package_id": _safe_text(closeout.get("run_package_id"), 160),
        "receipt_id": _safe_text(closeout.get("receipt_id"), 160),
        "target_table": _safe_text(closeout.get("target_table"), 160),
        "payload_row_count": _safe_int(closeout.get("payload_row_count")),
        "closeout_artifact_path": _safe_text(
            closeout.get("closeout_artifact_path")
        ),
        "post_closeout_inventory_plan_path": _safe_text(
            closeout.get("post_closeout_inventory_plan_path")
        ),
        "artifact_manifest_preserved": bool(
            closeout.get("manifest_writer_output_path")
            and closeout.get("manifest_postwrite_smoke_result_path")
            and closeout.get("manifest_backup_artifact_path")
        ),
        "side_effects_clear": side_effects_clear,
        "blocked_reasons": closeout_result.get("blocked_reasons", []),
    }


def _operator_inventory_summary(operator_inventory):
    operator_inventory = _as_dict(operator_inventory)
    query = _as_dict(operator_inventory.get("query_summary"))
    confirmations = _as_dict(operator_inventory.get("operator_confirmations"))
    return {
        "provided_keys": sorted(operator_inventory.keys()),
        "inventory_review_id": _safe_text(
            operator_inventory.get("inventory_review_id"), 160
        ),
        "closeout_id": _safe_text(operator_inventory.get("closeout_id"), 160),
        "run_package_id": _safe_text(operator_inventory.get("run_package_id"), 160),
        "receipt_id": _safe_text(operator_inventory.get("receipt_id"), 160),
        "target_table": _safe_text(operator_inventory.get("target_table"), 160),
        "payload_row_count": _safe_int(operator_inventory.get("payload_row_count")),
        "found_row_count": _safe_int(operator_inventory.get("found_row_count")),
        "missing_row_count": _safe_int(operator_inventory.get("missing_row_count")),
        "unexpected_duplicate_count": _safe_int(
            operator_inventory.get("unexpected_duplicate_count")
        ),
        "inventory_artifact_path": _safe_text(
            operator_inventory.get("inventory_artifact_path")
        ),
        "closeout_review_artifact_path": _safe_text(
            operator_inventory.get("closeout_review_artifact_path")
        ),
        "read_only_query_result_path": _safe_text(
            operator_inventory.get("read_only_query_result_path")
        ),
        "inventory_artifact_path_safe": _safe_path(
            operator_inventory.get("inventory_artifact_path"),
            prefixes=(ARTIFACT_PREFIX,),
            suffixes=(".json",),
        ),
        "closeout_review_artifact_path_safe": _safe_path(
            operator_inventory.get("closeout_review_artifact_path"),
            prefixes=(ARTIFACT_PREFIX,),
            suffixes=(".json",),
        ),
        "read_only_query_result_path_safe": _safe_path(
            operator_inventory.get("read_only_query_result_path"),
            prefixes=(ARTIFACT_PREFIX,),
            suffixes=(".json",),
        ),
        "query_type": _safe_text(query.get("query_type"), 80),
        "read_only_query_executed_by_operator": bool(
            query.get("read_only_query_executed_by_operator")
        ),
        "expected_rows_found": bool(query.get("expected_rows_found")),
        "row_count_matches_payload": bool(query.get("row_count_matches_payload")),
        "query_target_table": _safe_text(query.get("target_table"), 160),
        "closeout_reviewed": bool(confirmations.get("closeout_reviewed")),
        "inventory_read_only": bool(confirmations.get("inventory_read_only")),
        "no_missing_rows": bool(confirmations.get("no_missing_rows")),
        "no_unexpected_duplicates": bool(
            confirmations.get("no_unexpected_duplicates")
        ),
        "no_approval_token_payload": bool(
            confirmations.get("no_approval_token_payload")
        ),
        "no_api_cli_execution": bool(confirmations.get("no_api_cli_execution")),
        "no_api_database_write": bool(confirmations.get("no_api_database_write")),
        "no_api_inventory_query": bool(
            confirmations.get("no_api_inventory_query")
        ),
        "no_api_file_write": bool(confirmations.get("no_api_file_write")),
        "no_scheduler_attach": bool(confirmations.get("no_scheduler_attach")),
        "api_execution_allowed": bool(operator_inventory.get("api_execution_allowed")),
        "real_write_allowed_by_api": bool(
            operator_inventory.get("real_write_allowed_by_api")
        ),
        "secret_or_token_submitted_to_api": _contains_forbidden_key(
            operator_inventory,
            FORBIDDEN_SECRET_KEYS,
            safe_keys=SAFE_SECRET_METADATA_KEYS,
        ),
        "blocked_side_effects": _blocked_side_effects(operator_inventory),
    }


def _inventory_gates(*, closeout_received, inventory_received, closeout, inventory):
    operator_confirmed_boundaries = bool(
        inventory["closeout_reviewed"]
        and inventory["inventory_read_only"]
        and inventory["no_missing_rows"]
        and inventory["no_unexpected_duplicates"]
        and inventory["no_approval_token_payload"]
        and inventory["no_api_cli_execution"]
        and inventory["no_api_database_write"]
        and inventory["no_api_inventory_query"]
        and inventory["no_api_file_write"]
        and inventory["no_scheduler_attach"]
    )
    return [
        {
            "key": "writer_run_closeout_review_payload_or_result_received",
            "label": "已提供 writer run closeout review package 或已審核結果",
            "passed": closeout_received,
        },
        {
            "key": "writer_run_closeout_review_accepted",
            "label": "writer run closeout review gate 必須已通過",
            "passed": closeout["accepted"],
        },
        {
            "key": "writer_run_closeout_review_ready_for_inventory",
            "label": "closeout review 必須只放行到 post-closeout inventory review",
            "passed": closeout["ready_for_post_closeout_inventory_review"],
        },
        {
            "key": "writer_run_closeout_review_side_effect_free",
            "label": "closeout review 未顯示 API 執行、寫 DB、寫檔或掛 scheduler",
            "passed": closeout["side_effects_clear"],
        },
        {
            "key": "writer_run_closeout_review_identity_recorded",
            "label": "closeout review 必須保留 closeout_id、run_package_id 與 receipt_id",
            "passed": bool(
                closeout["closeout_id"]
                and closeout["run_package_id"]
                and closeout["receipt_id"]
            ),
        },
        {
            "key": "writer_run_closeout_review_manifest_preserved",
            "label": "closeout review 必須保留 writer output、post-write smoke 與 backup manifest",
            "passed": closeout["artifact_manifest_preserved"],
        },
        {
            "key": "post_closeout_inventory_payload_received",
            "label": "已提供 operator live inventory 摘要",
            "passed": inventory_received,
        },
        {
            "key": "post_closeout_inventory_identity_recorded",
            "label": "inventory 必須記錄 inventory_review_id、closeout_id、run_package_id 與 receipt_id",
            "passed": bool(
                inventory["inventory_review_id"]
                and inventory["closeout_id"]
                and inventory["run_package_id"]
                and inventory["receipt_id"]
            ),
        },
        {
            "key": "post_closeout_inventory_identity_matches_closeout",
            "label": "inventory identity 必須對齊 closeout review",
            "passed": bool(
                inventory["closeout_id"] == closeout["closeout_id"]
                and inventory["run_package_id"] == closeout["run_package_id"]
                and inventory["receipt_id"] == closeout["receipt_id"]
            ),
        },
        {
            "key": "post_closeout_inventory_target_table_safe",
            "label": "target table 必須是 market_alert_review_queue",
            "passed": inventory["target_table"] == TARGET_TABLE,
        },
        {
            "key": "post_closeout_inventory_row_count_matches_closeout",
            "label": "inventory row count 必須對齊 closeout payload rows",
            "passed": bool(
                inventory["payload_row_count"]
                and inventory["payload_row_count"] == closeout["payload_row_count"]
                and inventory["found_row_count"] == closeout["payload_row_count"]
                and inventory["missing_row_count"] == 0
                and inventory["unexpected_duplicate_count"] == 0
            ),
        },
        {
            "key": "post_closeout_inventory_artifact_paths_safe",
            "label": "inventory、closeout review 與 read-only query result paths 必須安全",
            "passed": bool(
                inventory["inventory_artifact_path_safe"]
                and inventory["closeout_review_artifact_path_safe"]
                and inventory["read_only_query_result_path_safe"]
            ),
        },
        {
            "key": "post_closeout_inventory_query_read_only",
            "label": "inventory 查核必須由操作員只讀查詢完成",
            "passed": bool(
                inventory["query_type"] == "read_only_select"
                and inventory["read_only_query_executed_by_operator"]
                and inventory["expected_rows_found"]
                and inventory["row_count_matches_payload"]
                and inventory["query_target_table"] == TARGET_TABLE
            ),
        },
        {
            "key": "post_closeout_inventory_operator_boundaries_confirmed",
            "label": "操作員確認只讀 inventory，且 API 未執行 CLI/DB/query/file/scheduler",
            "passed": operator_confirmed_boundaries,
        },
        {
            "key": "post_closeout_inventory_no_api_execution_or_real_write",
            "label": "inventory payload 不得允許 API execution 或 real write",
            "passed": bool(
                not inventory["api_execution_allowed"]
                and not inventory["real_write_allowed_by_api"]
            ),
        },
        {
            "key": "post_closeout_inventory_no_secret_or_token_key",
            "label": "inventory payload 不得包含 secret、cookie、password 或 token key",
            "passed": not inventory["secret_or_token_submitted_to_api"],
        },
        {
            "key": "post_closeout_inventory_side_effect_free",
            "label": "inventory payload 不得要求 API 寫檔、執行、查 DB、寫 DB 或掛 scheduler",
            "passed": not inventory["blocked_side_effects"],
        },
    ]


def build_mcp_fetch_candidate_queue_writer_post_closeout_inventory_review_preview(
    *,
    writer_run_closeout_review_package=None,
    writer_run_closeout_review_result=None,
    operator_inventory=None,
    phase=None,
):
    """建立 writer post-closeout inventory review；不執行查詢或寫入。"""
    writer_run_closeout_review_package = _as_dict(writer_run_closeout_review_package)
    closeout_result_received = bool(
        isinstance(writer_run_closeout_review_result, dict)
        and writer_run_closeout_review_result
    )
    inventory_valid_object = (
        isinstance(operator_inventory, dict) if operator_inventory is not None else True
    )
    inventory_payload = _as_dict(operator_inventory)
    closeout_received = bool(
        writer_run_closeout_review_package or closeout_result_received
    )
    closeout_result = (
        _closeout_review_from_inputs(
            writer_run_closeout_review_package,
            writer_run_closeout_review_result,
            phase,
        )
        if closeout_received
        else {}
    )
    payload_received = bool(
        closeout_received or inventory_payload or operator_inventory is not None
    )
    inventory_received = bool(inventory_payload)
    closeout = _closeout_review_summary(closeout_result)
    inventory = _operator_inventory_summary(inventory_payload)
    gates = _inventory_gates(
        closeout_received=closeout_received,
        inventory_received=inventory_received and inventory_valid_object,
        closeout=closeout,
        inventory=inventory,
    )
    blocked_reasons = [gate["key"] for gate in gates if not gate["passed"]]
    if not inventory_valid_object:
        blocked_reasons.append("operator_inventory_payload_valid_object")
    accepted = bool(payload_received and not blocked_reasons)

    return {
        "mode": (
            "mcp_fetch_candidate_queue_writer_post_closeout_inventory_review"
            if payload_received
            else "mcp_fetch_candidate_queue_writer_post_closeout_inventory_review_preview"
        ),
        "phase": phase,
        "post_closeout_inventory_review_payload_received": payload_received,
        "writer_run_closeout_review_received": closeout_received,
        "operator_inventory_received": inventory_received,
        "operator_inventory_valid_object": inventory_valid_object,
        "writer_run_closeout_review_accepted": closeout["accepted"],
        "mcp_fetch_candidate_queue_writer_post_closeout_inventory_review_accepted": (
            accepted
        ),
        "candidate_queue_writer_post_closeout_inventory_review_ready": accepted,
        "ready_for_candidate_queue_review_handoff": accepted,
        "ready_for_api_database_write": False,
        "ready_for_real_write": False,
        "ready_for_scheduler_attach": False,
        "network_request_allowed": False,
        "api_executes_cli": False,
        "api_reads_approval_token": False,
        "api_opens_database_connection": False,
        "api_writes_database": False,
        "api_writes_file": False,
        "api_uses_external_network": False,
        "api_inventory_query_executed": False,
        "post_closeout_query_executed_by_api": False,
        "payload_row_count": inventory["payload_row_count"],
        "gate_count": len(gates),
        "passed_gate_count": sum(1 for gate in gates if gate["passed"]),
        "blocked_reasons": blocked_reasons,
        "gates": gates,
        "writer_run_closeout_review_summary": closeout,
        "operator_inventory_summary": inventory,
        "sample_writer_post_closeout_inventory_review_package": (
            _sample_post_closeout_inventory_review_package()
        ),
        "next_operator_steps": [
            "Inventory review 通過後，只代表可進入 candidate queue review handoff",
            "API/UI 仍不得執行 DB inventory query、補寫 queue row、讀 token 或掛 scheduler",
            "後續 handoff 必須只引用已審核 artifact，不得從 UI/API 自動修補缺資料",
        ],
        "payload_persisted": False,
        "post_closeout_inventory_review_persisted": False,
        "post_closeout_inventory_persisted": False,
        "post_closeout_inventory_file_written": False,
        "inventory_file_written": False,
        "package_artifact_created": False,
        "database_session_created": False,
        "database_commit_executed": False,
        "database_write_executed": False,
        "external_network_executed": False,
        "cli_executed": False,
        "file_written": False,
        "writes_executed": False,
        "would_write_database": False,
        "scheduler_attached": False,
        "candidate_queue_created": False,
        "candidate_queue_persisted": False,
        "candidate_review_state_updated": False,
    }
