from __future__ import annotations

from pathlib import Path

from fastapi import FastAPI
from fastapi.testclient import TestClient

from src.api.v1 import agents
from src.api.v1.agents import router
from src.services.stockplatform_public_api_controlled_recovery_preflight import (
    load_latest_stockplatform_public_api_controlled_recovery_preflight,
)


def test_stockplatform_controlled_recovery_preflight_packages_api_502(
    tmp_path: Path,
):
    payload = load_latest_stockplatform_public_api_controlled_recovery_preflight(
        runtime_readback=_runtime_blocked(),
        route_source_path=_route_source(tmp_path),
    )

    assert (
        payload["schema_version"]
        == "stockplatform_public_api_controlled_recovery_preflight_v1"
    )
    assert payload["priority"] == "P0-006"
    assert payload["status"] == (
        "controlled_recovery_preflight_packaged_waiting_control_path_readback"
    )
    assert payload["api_layer_classification"] == (
        "edge_alive_api_upstream_unavailable"
    )
    assert payload["data_dependency_classification"] == "none"
    assert payload["target_selector"]["route_target_ready"] is True
    assert payload["source_of_truth_diff"]["status"] == (
        "route_source_present_runtime_api_upstream_blocked"
    )
    assert (
        payload["controlled_apply_policy"]["runtime_write_gate"]
        == "controlled_after_preflight"
    )
    assert payload["controlled_apply_policy"]["break_glass_required"] is False
    assert payload["controlled_apply_policy"]["current_apply_allowed"] is False
    assert "stockplatform_110_control_path_readback_required" in payload[
        "active_blockers"
    ]
    assert payload["rollups"]["controlled_recovery_candidate_packaged"] is True
    assert payload["rollups"]["host_control_path_readback_required"] is True
    assert payload["rollups"]["controlled_work_item_count"] == 5
    assert payload["rollups"]["post_apply_verifier_count"] == 4
    assert payload["rollups"]["learning_writeback_contract_count"] == 6
    assert payload["controlled_work_items"][0]["status"] == (
        "queued_waiting_control_path_readback"
    )
    assert payload["post_apply_verifiers"][0]["expected_http_status"] == 200
    assert payload["learning_writeback_contracts"][0]["writeback_mode"] == (
        "metadata_only"
    )
    assert payload["operation_boundaries"]["ssh_used"] is False
    assert payload["operation_boundaries"]["docker_command_performed"] is False
    assert payload["operation_boundaries"]["docker_daemon_restart_performed"] is False
    assert payload["operation_boundaries"]["host_reboot_performed"] is False
    assert payload["operation_boundaries"]["database_write_or_restore_performed"] is False
    assert payload["operation_boundaries"]["secret_value_collection_allowed"] is False


def test_stockplatform_controlled_recovery_preflight_not_required_when_ready(
    tmp_path: Path,
):
    payload = load_latest_stockplatform_public_api_controlled_recovery_preflight(
        runtime_readback=_runtime_ready(),
        route_source_path=_route_source(tmp_path),
    )

    assert payload["status"] == "stockplatform_public_api_recovery_preflight_not_required"
    assert payload["active_blockers"] == []
    assert payload["controlled_work_items"] == []
    assert payload["rollups"]["recovery_required"] is False


def test_stockplatform_controlled_recovery_preflight_packages_data_dependency(
    tmp_path: Path,
):
    payload = load_latest_stockplatform_public_api_controlled_recovery_preflight(
        runtime_readback=_runtime_data_dependency_blocked(),
        route_source_path=_route_source(tmp_path),
    )

    assert payload["status"] == (
        "controlled_data_dependency_preflight_packaged_waiting_control_path_readback"
    )
    assert payload["api_layer_classification"] == "api_live_data_dependency_not_ready"
    assert payload["data_dependency_classification"] == "postgres_not_ready"
    assert payload["safe_next_step"] == (
        "run_stockplatform_production_migration_path_after_control_channel_"
        "readback_then_public_api_verifier"
    )
    assert payload["source_of_truth_diff"]["status"] == (
        "route_source_present_api_live_data_dependency_not_ready"
    )
    assert payload["source_of_truth_diff"]["data_dependency_classification"] == (
        "postgres_not_ready"
    )
    assert payload["source_of_truth_diff"][
        "data_readiness_control_readback_status"
    ] == "blocked_stockplatform_postgres_not_ready"
    assert payload["source_of_truth_diff"][
        "data_readiness_control_receipt_provided"
    ] is True
    assert payload["data_readiness_control_readback"]["schema_version"] == (
        "stockplatform_postgres_readiness_or_data_source_readback_v1"
    )
    assert payload["rollups"][
        "postgres_readiness_or_data_source_readback_present"
    ] is True
    assert payload["rollups"][
        "postgres_readiness_or_data_source_receipt_provided"
    ] is True
    assert payload["controlled_apply_policy"]["current_apply_blocker"] == (
        "postgres_readiness_and_production_migration_control_path_readback_"
        "required_before_apply"
    )
    assert "read_only_data_dependency_status_inspection" in payload[
        "controlled_apply_policy"
    ]["allowed_scope"]
    assert "controlled_production_migration_path_after_dry_run" in payload[
        "controlled_apply_policy"
    ]["allowed_scope"]
    assert "fake_freshness_marker" in payload["controlled_action_candidates"][0][
        "forbidden_actions"
    ]
    assert payload["controlled_work_items"][1]["id"] == (
        "stockplatform-data-dependency-inspection"
    )
    assert payload["controlled_work_items"][2]["title"] == (
        "Production migration path and Postgres readiness preflight"
    )
    assert payload["controlled_action_candidates"][0]["id"] == (
        "read_only_data_dependency_inspection"
    )
    assert payload["controlled_action_candidates"][1]["id"] == (
        "production_migration_path_preflight"
    )
    assert payload["rollups"]["controlled_recovery_candidate_packaged"] is True
    assert payload["operation_boundaries"]["database_write_or_restore_performed"] is False


def test_stockplatform_controlled_recovery_preflight_prefers_live_data_classification(
    tmp_path: Path,
):
    payload = load_latest_stockplatform_public_api_controlled_recovery_preflight(
        runtime_readback=_runtime_data_dependency_non_postgres_blocked(),
        route_source_path=_route_source(tmp_path),
    )

    assert payload["status"] == (
        "controlled_data_dependency_preflight_packaged_waiting_control_path_readback"
    )
    assert payload["api_layer_classification"] == "api_live_data_dependency_not_ready"
    assert payload["data_dependency_classification"] == (
        "freshness_or_ingestion_not_ready"
    )
    assert payload["safe_next_step"] == (
        "run_stockplatform_data_dependency_source_contract_readback_"
        "then_public_api_verifier"
    )
    assert payload["controlled_apply_policy"]["current_apply_blocker"] == (
        "data_dependency_control_path_readback_required_before_source_"
        "freshness_or_postgres_contract_apply"
    )
    assert payload["source_contract_control_readback"]["schema_version"] == (
        "stockplatform_source_contract_control_readback_v1"
    )
    assert payload["source_of_truth_diff"][
        "source_contract_control_readback_status"
    ] == "blocked_stockplatform_source_contract_not_ready"
    assert payload["source_of_truth_diff"]["source_contract_receipt_provided"] is True
    assert payload["rollups"]["source_contract_readback_present"] is True
    assert payload["rollups"]["source_contract_receipt_provided"] is True
    assert payload["rollups"]["source_contract_non_ok_source_count"] == 2
    assert payload["controlled_action_candidates"][1]["id"] == (
        "source_freshness_contract_preflight"
    )


def test_stockplatform_controlled_recovery_preflight_routes_ai_recommendations(
    tmp_path: Path,
):
    payload = load_latest_stockplatform_public_api_controlled_recovery_preflight(
        runtime_readback=_runtime_ai_recommendations_stale_after_core_recovered(),
        route_source_path=_route_source(tmp_path),
    )

    assert payload["status"] == (
        "controlled_data_dependency_preflight_packaged_waiting_control_path_readback"
    )
    assert payload["api_layer_classification"] == "api_live_data_dependency_not_ready"
    assert payload["data_dependency_classification"] == (
        "ai_recommendations_stale_after_core_recovered"
    )
    assert payload["safe_next_step"] == (
        "run_stockplatform_ai_recommendation_pipeline_readback_then_"
        "public_api_verifier"
    )
    assert payload["controlled_apply_policy"]["current_apply_blocker"] == (
        "ai_recommendation_pipeline_readback_required_before_public_api_"
        "verifier"
    )
    assert "read_only_ai_recommendation_queue_status" in payload[
        "controlled_apply_policy"
    ]["allowed_scope"]
    assert payload["source_of_truth_diff"][
        "data_readiness_control_readback_status"
    ] == "blocked_stockplatform_ai_recommendations_stale_after_core_recovered"
    assert payload["source_of_truth_diff"][
        "source_contract_control_readback_status"
    ] == "stockplatform_source_contract_core_ready_ai_recommendations_stale"
    assert payload["controlled_work_items"][0]["id"] == (
        "stockplatform-ai-recommendation-control-path-readback"
    )
    assert payload["controlled_work_items"][2]["id"] == (
        "stockplatform-ai-recommendation-pipeline-preflight"
    )
    assert payload["controlled_action_candidates"][0]["id"] == (
        "read_only_ai_recommendation_pipeline_readback"
    )
    assert payload["controlled_action_candidates"][1]["id"] == (
        "ai_recommendation_pipeline_verifier_preflight"
    )
    assert payload["operation_boundaries"]["database_write_or_restore_performed"] is False


def test_stockplatform_controlled_recovery_preflight_endpoint_returns_payload(
    monkeypatch,
    tmp_path: Path,
):
    runtime_payload = _runtime_blocked()

    monkeypatch.setattr(
        agents,
        "load_latest_stockplatform_public_api_runtime_readback",
        lambda: runtime_payload,
    )

    def _load_preflight(*, runtime_readback: dict):
        assert runtime_readback is runtime_payload
        return load_latest_stockplatform_public_api_controlled_recovery_preflight(
            runtime_readback=runtime_readback,
            route_source_path=_route_source(tmp_path),
        )

    monkeypatch.setattr(
        agents,
        "load_latest_stockplatform_public_api_controlled_recovery_preflight",
        _load_preflight,
    )
    app = FastAPI()
    app.include_router(router, prefix="/api/v1")
    client = TestClient(app)

    response = client.get(
        "/api/v1/agents/stockplatform-public-api-controlled-recovery-preflight"
    )

    assert response.status_code == 200
    data = response.json()
    assert data["status"] == (
        "controlled_recovery_preflight_packaged_waiting_control_path_readback"
    )
    assert data["rollups"]["controlled_recovery_candidate_packaged"] is True


def _route_source(tmp_path: Path) -> Path:
    path = tmp_path / "188-all-sites.conf.j2"
    path.write_text(
        """
# Stock Platform - stock.wooo.work
server {
    server_name stock.wooo.work;
    location / {
        proxy_pass http://192.168.0.110:31235;
    }
}
# Next Site
""",
        encoding="utf-8",
    )
    return path


def _runtime_blocked() -> dict:
    return {
        "schema_version": "stockplatform_public_api_runtime_readback_v1",
        "priority": "P0-006",
        "status": "blocked_stockplatform_public_api_runtime_drift",
        "safe_next_step": (
            "recover_stockplatform_api_container_runtime_or_docker_control_path_"
            "without_daemon_restart_then_rerun_public_api_readback"
        ),
        "active_blockers": [
            "stockplatform_public_api_healthz_http_502",
            "stockplatform_freshness_http_502",
            "stockplatform_ingestion_http_502",
        ],
        "runtime_ready": False,
        "base_url": "https://stock.wooo.work",
        "readback": {
            "web_health_http_status": 200,
            "api_health_http_status": 502,
            "freshness_http_status": 502,
            "ingestion_http_status": 502,
        },
        "rollups": {
            "http_502_count": 3,
        },
    }


def _runtime_ready() -> dict:
    return {
        "schema_version": "stockplatform_public_api_runtime_readback_v1",
        "priority": "P0-006",
        "status": "stockplatform_public_api_runtime_ready",
        "runtime_ready": True,
        "base_url": "https://stock.wooo.work",
        "active_blockers": [],
        "readback": {
            "web_health_http_status": 200,
            "api_health_http_status": 200,
            "freshness_http_status": 200,
            "ingestion_http_status": 200,
            "postgres_not_ready": True,
        },
        "rollups": {
            "http_502_count": 0,
            "data_dependency_classification": "postgres_not_ready",
            "postgres_not_ready": True,
        },
    }


def _runtime_data_dependency_blocked() -> dict:
    return {
        "schema_version": "stockplatform_public_api_runtime_readback_v1",
        "priority": "P0-006",
        "status": "blocked_stockplatform_public_api_runtime_drift",
        "safe_next_step": "run_stockplatform_data_dependency_controlled_preflight",
        "active_blockers": [
            "stockplatform_freshness_postgres_not_ready",
            "stockplatform_ingestion_postgres_not_ready",
            "stockplatform_recovery_control_path_receipt_missing",
            "stockplatform_controlled_deploy_or_ssh_readback_required",
        ],
        "runtime_ready": False,
        "base_url": "https://stock.wooo.work",
        "readback": {
            "web_health_http_status": 200,
            "api_health_http_status": 200,
            "freshness_http_status": 200,
            "ingestion_http_status": 200,
        },
        "rollups": {
            "http_502_count": 0,
        },
        "data_readiness_control_readback": {
            "schema_version": (
                "stockplatform_postgres_readiness_or_data_source_readback_v1"
            ),
            "receipt_key": "stockplatform_postgres_readiness_or_data_source_readback",
            "status": "blocked_stockplatform_postgres_not_ready",
            "readback_present": True,
            "receipt_provided": True,
            "postgres_ready": False,
            "postgres_not_ready": True,
        },
    }


def _runtime_data_dependency_non_postgres_blocked() -> dict:
    payload = _runtime_data_dependency_blocked()
    payload["active_blockers"] = [
        "stockplatform_freshness_core_margin_short_daily_missing",
        "stockplatform_freshness_ai_recommendations_stale",
        "stockplatform_ingestion_status_not_ok",
        "stockplatform_postgres_not_ready",
    ]
    payload["readback"] = {
        "web_health_http_status": 200,
        "api_health_http_status": 200,
        "freshness_http_status": 200,
        "ingestion_http_status": 200,
        "data_dependency_classification": "freshness_or_ingestion_not_ready",
        "postgres_not_ready": False,
    }
    payload["rollups"] = {
        "http_502_count": 0,
        "data_dependency_classification": "freshness_or_ingestion_not_ready",
        "postgres_not_ready": False,
    }
    payload["data_readiness_control_readback"] = {
        "schema_version": "stockplatform_postgres_readiness_or_data_source_readback_v1",
        "receipt_key": "stockplatform_postgres_readiness_or_data_source_readback",
        "status": "blocked_stockplatform_data_dependency_not_ready",
        "readback_present": True,
        "receipt_provided": True,
        "postgres_ready": False,
        "postgres_not_ready": False,
    }
    payload["source_contract_control_readback"] = {
        "schema_version": "stockplatform_source_contract_control_readback_v1",
        "receipt_key": "stockplatform_source_contract_readback",
        "status": "blocked_stockplatform_source_contract_not_ready",
        "readback_present": True,
        "receipt_provided": True,
        "source_contract_ready": False,
        "non_ok_source_count": 2,
        "active_blockers": [
            "stockplatform_freshness_core_margin_short_daily_missing",
            "stockplatform_freshness_ai_recommendations_stale",
        ],
        "blocking_sources": [
            {
                "source": "core.margin_short_daily",
                "category": "freshness",
                "status": "missing",
            },
            {
                "source": "ai.recommendations",
                "category": "freshness",
                "status": "stale",
            },
        ],
    }
    return payload


def _runtime_ai_recommendations_stale_after_core_recovered() -> dict:
    payload = _runtime_data_dependency_non_postgres_blocked()
    payload["safe_next_step"] = (
        "run_stockplatform_ai_recommendation_pipeline_readback_then_rerun_"
        "public_api_verifier"
    )
    payload["active_blockers"] = [
        "stockplatform_freshness_ai_recommendations_stale",
        "stockplatform_post_apply_public_api_verifier_not_green",
    ]
    payload["readback"].update(
        {
            "freshness_status": "blocked",
            "ingestion_status": "ok",
            "freshness_blockers": ["ai_recommendations_stale"],
            "ingestion_blockers": [],
            "data_dependency_classification": (
                "ai_recommendations_stale_after_core_recovered"
            ),
        }
    )
    payload["rollups"]["data_dependency_classification"] = (
        "ai_recommendations_stale_after_core_recovered"
    )
    payload["data_readiness_control_readback"]["status"] = (
        "blocked_stockplatform_ai_recommendations_stale_after_core_recovered"
    )
    payload["source_contract_control_readback"]["status"] = (
        "stockplatform_source_contract_core_ready_ai_recommendations_stale"
    )
    payload["source_contract_control_readback"]["active_blockers"] = [
        "stockplatform_freshness_ai_recommendations_stale"
    ]
    payload["source_contract_control_readback"]["blocking_sources"] = [
        {
            "source": "ai.recommendations",
            "category": "freshness",
            "status": "stale",
        },
    ]
    return payload
