"""市場情報 MCP 完整度稽核 preview。

本模組只彙整既有 MCP readiness、tool contract、deploy preflight、activation
runbook 與 fetch gate；不呼叫 MCP server、不執行 docker/SSH、不連 DB、不寫入。
"""

from services.market_intel.mcp_activation_runbook import (
    build_mcp_activation_runbook_preview,
)
from services.market_intel.mcp_contract import build_mcp_tool_contract_preview
from services.market_intel.mcp_deploy_preflight import build_mcp_deploy_preflight_plan
from services.market_intel.mcp_fetch_gate import build_mcp_fetch_gate_preview
from services.market_intel.mcp_readiness import (
    EXPECTED_EXTERNAL_SERVERS,
    build_mcp_readiness_plan,
)


def _blocked_reasons(gates):
    return [item["key"] for item in gates if not item["passed"]]


def _none_executed(payload, keys):
    return all(not payload.get(key) for key in keys)


def build_mcp_completion_audit_preview(
    *,
    runtime_status,
    readiness=None,
    tool_contract=None,
    deploy_preflight=None,
    activation_runbook=None,
    fetch_gate=None,
):
    """建立 MCP 外部/內部完整度稽核；預設全程 read-only planned preview。"""
    readiness = readiness or build_mcp_readiness_plan(execute_requested=False)
    tool_contract = tool_contract or build_mcp_tool_contract_preview()
    deploy_preflight = deploy_preflight or build_mcp_deploy_preflight_plan()
    activation_runbook = activation_runbook or build_mcp_activation_runbook_preview(
        preflight=deploy_preflight,
        readiness=readiness,
    )
    fetch_gate = fetch_gate or build_mcp_fetch_gate_preview(
        runtime_status,
        fetch_requested=False,
        execute_readiness=False,
        readiness=readiness,
    )

    external_design_checks = {
        "expected_servers_declared": set(EXPECTED_EXTERNAL_SERVERS)
        <= {item.get("server") for item in readiness.get("server_statuses", [])},
        "compose_file_present": bool(
            deploy_preflight.get("checks", {}).get("compose_file_present")
        ),
        "expected_services_declared": bool(
            deploy_preflight.get("checks", {}).get("all_expected_services_declared")
        ),
        "expected_containers_declared": bool(
            deploy_preflight.get("checks", {}).get("all_expected_containers_declared")
        ),
        "localhost_ports_only": bool(
            deploy_preflight.get("checks", {}).get(
                "all_public_mcp_ports_localhost_only"
            )
        ),
        "readonly_postgres_design": bool(
            deploy_preflight.get("checks", {}).get("postgres_readonly_role_required")
            and deploy_preflight.get("checks", {}).get(
                "postgres_allowed_tables_limited"
            )
        ),
        "readonly_filesystem_mounts": bool(
            deploy_preflight.get("checks", {}).get("filesystem_mounts_read_only")
        ),
    }
    external_design_complete = all(external_design_checks.values())
    external_runtime_complete = bool(readiness.get("external_mcp_complete"))
    internal_contract_complete = bool(tool_contract.get("contract_ready"))
    internal_runtime_complete = bool(readiness.get("internal_mcp_complete"))
    market_intel_mcp_integrated = bool(readiness.get("market_intel_mcp_integrated"))
    activation_runbook_present = bool(
        activation_runbook.get("mode") == "mcp_activation_runbook_preview"
        and activation_runbook.get("stages")
    )
    fetch_gate_present = bool(fetch_gate.get("mode") == "mcp_fetch_gate_planned")
    preview_side_effect_free = bool(
        _none_executed(
            readiness,
            (
                "database_session_created",
                "database_write_executed",
                "database_commit_executed",
                "external_network_executed",
                "scheduler_attached",
                "writes_executed",
                "would_write_database",
            ),
        )
        and _none_executed(
            tool_contract,
            (
                "database_session_created",
                "database_write_executed",
                "database_commit_executed",
                "external_network_executed",
                "scheduler_attached",
                "writes_executed",
                "would_write_database",
            ),
        )
        and _none_executed(
            deploy_preflight,
            (
                "deployment_actions_executed",
                "docker_command_executed",
                "ssh_command_executed",
                "database_session_created",
                "database_write_executed",
                "database_commit_executed",
                "external_network_executed",
                "scheduler_attached",
                "writes_executed",
                "would_write_database",
            ),
        )
        and _none_executed(
            activation_runbook,
            (
                "deployment_actions_executed",
                "docker_command_executed",
                "ssh_command_executed",
                "database_session_created",
                "database_write_executed",
                "database_commit_executed",
                "external_network_executed",
                "scheduler_attached",
                "writes_executed",
                "would_write_database",
            ),
        )
        and _none_executed(
            fetch_gate,
            (
                "network_request_allowed",
                "database_session_created",
                "database_write_executed",
                "database_commit_executed",
                "external_network_executed",
                "scheduler_attached",
                "writes_executed",
                "would_write_database",
            ),
        )
    )

    gates = [
        {
            "key": "external_mcp_design_complete",
            "passed": external_design_complete,
            "label": "外部 MCP compose、localhost port、唯讀邊界與 server 清單已定義",
        },
        {
            "key": "external_mcp_runtime_complete",
            "passed": external_runtime_complete,
            "label": "外部 MCP health 已執行且 router 已啟用",
        },
        {
            "key": "internal_mcp_contract_complete",
            "passed": internal_contract_complete,
            "label": "market_intel 內部 MCP tool contract 已被 router 白名單覆蓋",
        },
        {
            "key": "internal_mcp_runtime_complete",
            "passed": internal_runtime_complete,
            "label": "mcp_calls telemetry / read-only 查詢鏈路已在執行態確認",
        },
        {
            "key": "market_intel_mcp_integrated",
            "passed": market_intel_mcp_integrated,
            "label": "市場情報呼叫端已納入 MCP registry",
        },
        {
            "key": "activation_runbook_present",
            "passed": activation_runbook_present,
            "label": "外部 MCP 啟用順序、health gate 與 fallback 已建立",
        },
        {
            "key": "manual_fetch_gate_present",
            "passed": fetch_gate_present,
            "label": "人工 fetch 安全閘門已建立且預設關閉",
        },
        {
            "key": "preview_side_effect_free",
            "passed": preview_side_effect_free,
            "label": "本 API 不啟動 MCP、不連 DB、不寫入、不抓外站",
        },
    ]
    passed_gate_count = sum(1 for item in gates if item["passed"])

    return {
        "mode": "mcp_completion_audit_preview",
        "audit_ready_for_operator_review": True,
        "audit_preview_safe": preview_side_effect_free,
        "overall_mcp_completion_percent": round(passed_gate_count / len(gates) * 100),
        "external_mcp_complete": external_runtime_complete,
        "external_mcp_design_complete": external_design_complete,
        "external_mcp_runtime_complete": external_runtime_complete,
        "internal_mcp_complete": internal_runtime_complete,
        "internal_mcp_contract_complete": internal_contract_complete,
        "internal_mcp_runtime_complete": internal_runtime_complete,
        "market_intel_mcp_integrated": market_intel_mcp_integrated,
        "ready_for_external_mcp_activation": bool(
            activation_runbook.get("ready_for_operator_activation")
        ),
        "ready_for_internal_mcp_use": bool(
            internal_contract_complete and market_intel_mcp_integrated
        ),
        "ready_for_manual_fetch": bool(fetch_gate.get("manual_fetch_gate_open")),
        "gates": gates,
        "blocked_reasons": _blocked_reasons(gates),
        "external_mcp_summary": {
            "expected_servers": list(EXPECTED_EXTERNAL_SERVERS),
            "configured_servers": [
                item["server"]
                for item in readiness.get("server_statuses", [])
                if item.get("configured")
            ],
            "health_checked": bool(readiness.get("execute_requested")),
            "router_enabled": bool(readiness.get("router_enabled")),
            "design_checks": external_design_checks,
            "runtime_blocked_reasons": readiness.get("blocked_reasons", []),
        },
        "internal_mcp_summary": {
            "caller": tool_contract.get("caller"),
            "tool_count": int(tool_contract.get("tool_count") or 0),
            "expected_tool_names": tool_contract.get("expected_tool_names", []),
            "contract_ready": internal_contract_complete,
            "telemetry_mode": readiness.get("telemetry", {}).get("mode"),
            "telemetry_table_exists": bool(
                readiness.get("telemetry", {}).get("table_exists")
            ),
            "read_only_query_executed": bool(
                readiness.get("telemetry", {}).get("read_only_query_executed")
            ),
        },
        "activation_summary": {
            "mode": activation_runbook.get("mode"),
            "ready_for_operator_activation": bool(
                activation_runbook.get("ready_for_operator_activation")
            ),
            "stage_count": len(activation_runbook.get("stages", [])),
            "blocked_reasons": activation_runbook.get("blocked_reasons", []),
            "fallback_count": len(activation_runbook.get("fallback_plan", [])),
        },
        "fetch_gate_summary": {
            "mode": fetch_gate.get("mode"),
            "manual_fetch_gate_open": bool(fetch_gate.get("manual_fetch_gate_open")),
            "network_request_allowed": bool(fetch_gate.get("network_request_allowed")),
            "blocked_reasons": fetch_gate.get("blocked_reasons", []),
        },
        "next_operator_steps": [
            "補齊外部 MCP 必要 env 後，再由操作員依 runbook 啟動 docker-compose.mcp.yml",
            "四個 localhost health endpoint 全部 200 後，才允許開 MCP_ROUTER_ENABLED",
            "router 開啟後以 execute=true 跑 read-only MCP readiness smoke",
            "人工 fetch 仍需先通過 MCP fetch gate，且不得寫 DB 或掛 scheduler",
        ],
        "mcp_readiness": readiness,
        "mcp_tool_contract": tool_contract,
        "mcp_deploy_preflight": deploy_preflight,
        "mcp_activation_runbook": activation_runbook,
        "mcp_fetch_gate": fetch_gate,
        "api_executes_health_check": False,
        "api_executes_docker": False,
        "api_executes_ssh": False,
        "api_opens_database_connection": False,
        "api_writes_database": False,
        "api_uses_external_network": False,
        "database_session_created": False,
        "database_write_executed": False,
        "database_commit_executed": False,
        "external_network_executed": False,
        "scheduler_attached": False,
        "writes_executed": False,
        "would_write_database": False,
    }


def build_mcp_completion_audit_for_runtime(*, runtime_status, phase):
    """以 service runtime 狀態組裝完整度稽核，並在子 payload 標記 phase。"""
    readiness = build_mcp_readiness_plan(execute_requested=False)
    readiness["phase"] = phase
    tool_contract = build_mcp_tool_contract_preview()
    tool_contract["phase"] = phase
    deploy_preflight = build_mcp_deploy_preflight_plan()
    deploy_preflight["phase"] = phase
    activation_runbook = build_mcp_activation_runbook_preview(
        preflight=deploy_preflight,
        readiness=readiness,
    )
    activation_runbook["phase"] = phase
    fetch_gate = build_mcp_fetch_gate_preview(
        runtime_status,
        fetch_requested=False,
        execute_readiness=False,
        readiness=readiness,
    )
    fetch_gate["phase"] = phase
    audit = build_mcp_completion_audit_preview(
        runtime_status=runtime_status,
        readiness=readiness,
        tool_contract=tool_contract,
        deploy_preflight=deploy_preflight,
        activation_runbook=activation_runbook,
        fetch_gate=fetch_gate,
    )
    audit["phase"] = phase
    return audit
