"""
IwoooS Wazuh managed host coverage readback.

This service exposes the committed Wazuh managed-host coverage snapshot as a
public-safe, alias-only payload. It never queries Wazuh, reads secrets, reenrolls
agents, restarts services, writes hosts, or enables active response.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from src.services.snapshot_paths import default_security_dir

_DEFAULT_SECURITY_DIR = default_security_dir(Path(__file__))
_SNAPSHOT_FILE = "wazuh-managed-host-coverage-gate.snapshot.json"
_EXPECTED_SCHEMA = "wazuh_managed_host_coverage_gate_v1"

_REQUIRED_FALSE_BOUNDARIES = {
    "host_write_authorized",
    "kali_active_scan_authorized",
    "raw_wazuh_payload_storage_allowed",
    "runtime_execution_authorized",
    "secret_value_collection_allowed",
    "wazuh_active_response_authorized",
    "wazuh_agent_reenroll_authorized",
    "wazuh_agent_restart_authorized",
    "wazuh_api_live_query_authorized",
    "wazuh_manager_restart_authorized",
}

_STATUS_LABELS = {
    "agent_active_transport_observed": "代理服務與傳輸連線已觀察，管理器清單 evidence 已驗收",
    "no_agent_transport_observed": "管理器清單 evidence 已驗收，仍需 runtime/服務狀態獨立確認",
    "ssh_readback_blocked": "管理器清單 evidence 已驗收，合法只讀讀回與 runtime postcheck 仍需獨立 gate",
}

_NEXT_GATE_LABELS = {
    "manager_registry_cross_check": "補管理器清單交叉驗收",
    "agent_install_or_service_owner_decision": "補代理安裝狀態或服務負責人決策",
    "read_only_access_or_owner_export": "補只讀 access 或脫敏 owner export",
    "runtime_gate_owner_review": "進 runtime gate owner review 與 postcheck",
}


def load_latest_iwooos_wazuh_managed_host_coverage(
    security_dir: Path | None = None,
) -> dict[str, Any]:
    """Load Wazuh managed-host coverage as an alias-only public readback."""
    directory = security_dir or _DEFAULT_SECURITY_DIR
    snapshot = _load_snapshot(directory)
    _require_boundaries(snapshot)

    summary = _summary(snapshot)
    matrix = _host_scope_matrix(snapshot)
    evidence = _required_evidence(snapshot)
    merged_summary = {
        "expected_host_scope_count": _int(summary.get("expected_host_scope_count")),
        "manager_service_active_observed_count": _int(summary.get("manager_service_active_observed_count")),
        "manager_api_unauthenticated_response_count": _int(summary.get("manager_api_unauthenticated_response_count")),
        "manager_transport_established_connection_count": _int(
            summary.get("manager_transport_established_connection_count")
        ),
        "direct_agent_active_observed_count": _int(summary.get("direct_agent_active_observed_count")),
        "direct_agent_transport_observed_count": _int(summary.get("direct_agent_transport_observed_count")),
        "direct_agent_missing_or_no_transport_count": _int(
            summary.get("direct_agent_missing_or_no_transport_count")
        ),
        "ssh_readback_blocked_count": _int(summary.get("ssh_readback_blocked_count")),
        "manager_registry_accepted_count": _int(summary.get("manager_registry_accepted_count")),
        "manager_registry_gap_count": max(
            _int(summary.get("expected_host_scope_count")) - _int(summary.get("manager_registry_accepted_count")),
            0,
        ),
        "dashboard_api_degraded_observed_count": _int(summary.get("dashboard_api_degraded_observed_count")),
        "live_metadata_env_enabled_count": _int(summary.get("live_metadata_env_enabled_count")),
        "active_response_authorized_count": _int(summary.get("active_response_authorized_count")),
        "host_write_authorized_count": _int(summary.get("host_write_authorized_count")),
        "agent_reenroll_authorized_count": _int(summary.get("agent_reenroll_authorized_count")),
        "agent_restart_authorized_count": _int(summary.get("agent_restart_authorized_count")),
        "runtime_gate_count": _int(summary.get("runtime_gate_count")),
        "host_scope_matrix_count": len(matrix),
        "required_evidence_before_green_count": len(evidence),
        "required_evidence_accepted_count": sum(1 for item in evidence if item.get("accepted") is True),
    }

    return {
        "schema_version": "iwooos_wazuh_managed_host_coverage_readback_v1",
        "status": snapshot.get("status", "blocked_waiting_full_host_registry_readback"),
        "mode": "committed_snapshot_readback_alias_only_no_wazuh_live_query",
        "source_refs": [
            f"docs/security/{_SNAPSHOT_FILE}",
            "scripts/security/wazuh-managed-host-coverage-gate.py",
        ],
        "summary": merged_summary,
        "host_scope_matrix": matrix,
        "required_evidence_before_green": evidence,
        "operator_interpretation": _list_of_strings(snapshot.get("operator_interpretation")),
        "forbidden_completion_claims": _list_of_strings(snapshot.get("forbidden_completion_claims")),
        "forbidden_actions": _list_of_strings(snapshot.get("forbidden_actions")),
        "boundary_markers": _boundary_markers(merged_summary),
        "boundaries": {
            "wazuh_api_live_query_authorized": False,
            "wazuh_active_response_authorized": False,
            "wazuh_agent_reenroll_authorized": False,
            "wazuh_agent_restart_authorized": False,
            "wazuh_manager_restart_authorized": False,
            "host_write_authorized": False,
            "kali_active_scan_authorized": False,
            "secret_value_collection_allowed": False,
            "raw_wazuh_payload_storage_allowed": False,
            "runtime_execution_authorized": False,
            "not_authorization": True,
        },
        "no_false_green_rules": [
            "Wazuh Dashboard 可見不等於 manager registry 已恢復",
            "transport 連線、agent service active 或 HTTP 200 不可替代逐主機 registry matrix",
            "manager registry accepted 只代表 committed redacted evidence 覆蓋公開別名，不代表 runtime 授權",
            "重新註冊、重啟、active response、主機寫入、Nginx、firewall、Kali 掃描與機密調整都不是此讀回授權",
        ],
    }


def _load_snapshot(directory: Path) -> dict[str, Any]:
    path = directory / _SNAPSHOT_FILE
    if not path.is_file():
        raise FileNotFoundError(f"{path}: Wazuh 受管主機覆蓋快照不存在")
    with path.open(encoding="utf-8") as handle:
        payload = json.load(handle)
    if not isinstance(payload, dict):
        raise ValueError(f"{path}: expected JSON object")
    if payload.get("schema_version") != _EXPECTED_SCHEMA:
        raise ValueError(f"{path}: expected schema_version={_EXPECTED_SCHEMA}")
    return payload


def _summary(payload: dict[str, Any]) -> dict[str, Any]:
    summary = payload.get("summary")
    return summary if isinstance(summary, dict) else {}


def _int(value: Any) -> int:
    return value if isinstance(value, int) else 0


def _list_of_strings(value: Any) -> list[str]:
    if not isinstance(value, list):
        return []
    return [item for item in value if isinstance(item, str)]


def _host_scope_matrix(payload: dict[str, Any]) -> list[dict[str, Any]]:
    raw_items = payload.get("host_scope_matrix")
    if not isinstance(raw_items, list):
        raise ValueError("Wazuh 受管主機覆蓋 host_scope_matrix 缺失")

    matrix: list[dict[str, Any]] = []
    for raw_item in raw_items:
        if not isinstance(raw_item, dict):
            raise ValueError("Wazuh 受管主機覆蓋 host_scope_matrix 必須是 object list")
        node_id = str(raw_item.get("node_id", ""))
        role = str(raw_item.get("role", ""))
        readback_status = str(raw_item.get("readback_status", ""))
        next_gate = str(raw_item.get("next_gate", ""))
        if not node_id.startswith("managed_"):
            raise ValueError(f"Wazuh 受管主機覆蓋 node_id 必須維持公開別名：{node_id}")
        manager_registry_accepted = raw_item.get("manager_registry_accepted") is True
        matrix.append(
            {
                "node_id": node_id,
                "role": role,
                "readback_status": readback_status,
                "readback_status_label": _STATUS_LABELS.get(readback_status, "待補只讀讀回"),
                "next_gate": next_gate,
                "next_gate_label": _NEXT_GATE_LABELS.get(next_gate, "待補負責人驗收"),
                "manager_registry_accepted": manager_registry_accepted,
            }
        )
    return matrix


def _required_evidence(payload: dict[str, Any]) -> list[dict[str, Any]]:
    raw_items = payload.get("required_evidence_before_green")
    if not isinstance(raw_items, list):
        raise ValueError("Wazuh 受管主機覆蓋 required_evidence_before_green 缺失")
    evidence: list[dict[str, Any]] = []
    for raw_item in raw_items:
        if not isinstance(raw_item, dict):
            raise ValueError("Wazuh 受管主機覆蓋 required_evidence_before_green 必須是 object list")
        evidence_id = str(raw_item.get("evidence_id", ""))
        accepted = raw_item.get("accepted") is True
        evidence.append({"evidence_id": evidence_id, "accepted": accepted})
    return evidence


def _boundary_markers(summary: dict[str, int]) -> list[str]:
    return [
        "wazuh_managed_host_coverage_gate_visible=true",
        f"wazuh_managed_host_coverage_expected_host_scope_count={summary['expected_host_scope_count']}",
        f"wazuh_managed_host_coverage_host_scope_matrix_count={summary['host_scope_matrix_count']}",
        f"wazuh_managed_host_coverage_direct_agent_active_observed_count={summary['direct_agent_active_observed_count']}",
        f"wazuh_managed_host_coverage_direct_agent_missing_or_no_transport_count={summary['direct_agent_missing_or_no_transport_count']}",
        f"wazuh_managed_host_coverage_ssh_readback_blocked_count={summary['ssh_readback_blocked_count']}",
        f"wazuh_managed_host_coverage_manager_registry_accepted_count={summary['manager_registry_accepted_count']}",
        f"wazuh_managed_host_coverage_manager_registry_gap_count={summary['manager_registry_gap_count']}",
        f"wazuh_managed_host_coverage_required_evidence_before_green_count={summary['required_evidence_before_green_count']}",
        f"wazuh_managed_host_coverage_required_evidence_accepted_count={summary['required_evidence_accepted_count']}",
        f"wazuh_managed_host_coverage_dashboard_api_degraded_observed_count={summary['dashboard_api_degraded_observed_count']}",
        f"wazuh_managed_host_coverage_live_metadata_env_enabled_count={summary['live_metadata_env_enabled_count']}",
        f"wazuh_managed_host_coverage_runtime_gate_count={summary['runtime_gate_count']}",
        f"wazuh_agent_reenroll_authorized_count={summary['agent_reenroll_authorized_count']}",
        f"wazuh_agent_restart_authorized_count={summary['agent_restart_authorized_count']}",
        "wazuh_agent_reenroll_authorized=false",
        "wazuh_agent_restart_authorized=false",
        "wazuh_manager_restart_authorized=false",
        "wazuh_active_response_authorized=false",
        "host_write_authorized=false",
        "secret_value_collection_allowed=false",
        "raw_wazuh_payload_storage_allowed=false",
        "runtime_execution_authorized=false",
        "not_authorization=true",
    ]


def _require_boundaries(payload: dict[str, Any]) -> None:
    summary = _summary(payload)
    for key in (
        "live_metadata_env_enabled_count",
        "active_response_authorized_count",
        "host_write_authorized_count",
        "agent_reenroll_authorized_count",
        "agent_restart_authorized_count",
        "runtime_gate_count",
    ):
        if _int(summary.get(key)) != 0:
            raise ValueError(f"Wazuh 受管主機覆蓋 summary.{key} 必須維持 0")

    expected_hosts = _int(summary.get("expected_host_scope_count"))
    manager_accepted = _int(summary.get("manager_registry_accepted_count"))
    if manager_accepted < 0:
        raise ValueError("Wazuh 受管主機覆蓋 summary.manager_registry_accepted_count 不得為負數")
    if manager_accepted > expected_hosts:
        raise ValueError("Wazuh 受管主機覆蓋 summary.manager_registry_accepted_count 不得大於 expected_host_scope_count")

    raw_matrix = payload.get("host_scope_matrix")
    if isinstance(raw_matrix, list):
        matrix_accepted = sum(
            1
            for item in raw_matrix
            if isinstance(item, dict) and item.get("manager_registry_accepted") is True
        )
        if matrix_accepted != manager_accepted:
            raise ValueError("Wazuh 受管主機覆蓋 manager registry accepted matrix/count 不一致")

    boundaries = payload.get("execution_boundaries")
    if not isinstance(boundaries, dict):
        raise ValueError("Wazuh 受管主機覆蓋 execution_boundaries 缺失")
    for key in _REQUIRED_FALSE_BOUNDARIES:
        if boundaries.get(key) is not False:
            raise ValueError(f"Wazuh 受管主機覆蓋 execution_boundaries.{key} 必須維持 false")
    if boundaries.get("not_authorization") is not True:
        raise ValueError("Wazuh 受管主機覆蓋 not_authorization 必須維持 true")
