from __future__ import annotations

import json
from datetime import datetime, timedelta, timezone
from pathlib import Path

import polars as pl
import pytest
from fastapi.testclient import TestClient

pytest.importorskip("torch")
pytest.importorskip("xgboost")

from uforia.api.app import create_app
from uforia.api.settings import ApiSettings
from uforia.microstructure import (
    build_microstructure_feature_series,
    build_microstructure_label_series,
    evaluate_microstructure_model,
    export_microstructure_model,
    generate_microstructure_model_output,
    import_crypto_microstructure_history,
    train_microstructure_model,
)
from uforia.microstructure.live import _read_jsonl_partitioned, _read_market_events
from uforia.microstructure.training import SEQUENCE_LENGTH, TcnClassifier, _validation_split
from uforia.storage import DATASET_SPECS, DatasetName, DatasetStore


def _frame_for_dataset(dataset: DatasetName, rows: list[dict[str, object]]) -> pl.DataFrame:
    schema = DATASET_SPECS[dataset].schema
    normalized = [{column: row.get(column) for column in schema} for row in rows]
    return pl.DataFrame(normalized, schema=schema)


def test_import_crypto_microstructure_history(tmp_path: Path) -> None:
    root = tmp_path / "legacy"
    (root / "data" / "parquet" / "bars" / "BTC" / "binance_spot").mkdir(parents=True)
    (root / "data" / "parquet" / "features" / "BTC" / "1m").mkdir(parents=True)
    (root / "data" / "parquet" / "funding" / "BTC" / "binance_futures").mkdir(parents=True)
    base = datetime(2026, 3, 1, 12, tzinfo=timezone.utc)
    pl.DataFrame(
        [
            {
                "timestamp": base,
                "open": 50_000.0,
                "high": 50_100.0,
                "low": 49_900.0,
                "close": 50_050.0,
                "volume": 12.0,
                "buy_volume": 7.0,
                "sell_volume": 5.0,
                "trade_count": 100,
                "vwap": 50_020.0,
                "microprice": 50_040.0,
                "spread": 2.0,
                "depth_bid_5": 100.0,
                "depth_ask_5": 95.0,
                "is_gap": False,
            }
        ]
    ).write_parquet(
        root / "data" / "parquet" / "bars" / "BTC" / "binance_spot" / "2026-03-01.parquet"
    )
    pl.DataFrame(
        [
            {
                "timestamp": base,
                "close": 50_050.0,
                "micro_tilt": 0.001,
                "imb_5": 0.12,
                "tir_60": 0.08,
                "rv_5": 0.02,
                "funding_rate": 0.0001,
            }
        ]
    ).write_parquet(root / "data" / "parquet" / "features" / "BTC" / "1m" / "2026-03-01.parquet")
    pl.DataFrame(
        [{"timestamp": base, "rate": 0.0002}]
    ).write_parquet(
        root / "data" / "parquet" / "funding" / "BTC" / "binance_futures" / "2026-03-01.parquet"
    )

    store = DatasetStore(tmp_path / "store")
    with pytest.raises(
        RuntimeError,
        match="Historical parquet import has been removed. Load microstructure history into Postgres before training.",
    ):
        import_crypto_microstructure_history(store, root, assets=("BTC",))


def test_microstructure_training_and_inference_roundtrip(tmp_path: Path) -> None:
    store = DatasetStore(tmp_path / "store")
    base = datetime(2026, 3, 1, 0, tzinfo=timezone.utc)
    feature_rows = []
    label_rows = []
    for index in range(160):
        ts = base + timedelta(minutes=index)
        feature_rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "asset": "BTC",
                "horizon": "1m",
                "source": "tcn_boost_features_v2",
                "bar_size_secs": 60,
                "mid_price": 50_000 + index,
                "return_1": 0.001 * (index % 3 - 1),
                "return_5": 0.002 * (index % 5 - 2),
                "realized_vol": 0.01 + 0.0001 * index,
                "book_imbalance": 1.0 if index % 3 == 2 else -1.0 if index % 3 == 0 else 0.0,
                "microprice_tilt": 0.001 * (index % 2),
                "order_flow_imbalance": 0.5 if index % 3 == 2 else -0.5 if index % 3 == 0 else 0.0,
                "cumulative_delta": float(index),
                "cum_delta_10": float(index),
                "cum_delta_30": float(index),
                "cum_delta_50": float(index),
                "spread_rel": 0.0001,
                "depth_total": 195.0,
                "volume_delta": 2.0,
                "microprice_gap": 1.0,
                "ofi_mean_12": 0.0,
                "ofi_std_12": 1.0,
                "imbalance_mean_12": 0.0,
                "spread_rel_mean_12": 0.0001,
                "depth_change_1": 0.01,
                "microprice_tilt_change_5": 0.001,
                "basis_bps": 0.0,
                "funding_rate": 0.0001,
                "oi_value": 10_000.0 + index,
                "liquidation_volume": 0.0,
                "iv_atm": 0.6,
                "iv_skew_25d": -0.04,
                "iv_rv_gap": 0.59,
                "cross_venue_spread": 3.0,
                "horizon_secs": 60,
                "feature_count": 13,
                "feature_payload": "{}",
                "quality_flag": "ok",
            }
        )
        label_rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "asset": "BTC",
                "horizon": "1m",
                "source": "tcn_boost_cost_aware_v2",
                "forward_return_bps": 5.0 if index % 3 == 2 else -5.0 if index % 3 == 0 else 0.0,
                "forward_microprice_return_bps": (
                    5.0 if index % 3 == 2 else -5.0 if index % 3 == 0 else 0.0
                ),
                "forward_move_abs_bps": 5.0,
                "label": 2 if index % 3 == 2 else 0 if index % 3 == 0 else 1,
                "tau_bps": 2.5,
                "bar_size_secs": 60,
                "label_horizon_steps": 1,
                "horizon_seconds": 60,
                "quality_flag": "ok",
            }
        )
    store.write(
        DatasetName.MICROSTRUCTURE_FEATURE_SERIES,
        _frame_for_dataset(DatasetName.MICROSTRUCTURE_FEATURE_SERIES, feature_rows),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_LABEL_SERIES,
        _frame_for_dataset(DatasetName.MICROSTRUCTURE_LABEL_SERIES, label_rows),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_REGIME_SERIES,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_REGIME_SERIES,
            [
                {
                    "ts": row["ts"],
                    "date": row["date"],
                    "asset": "BTC",
                    "source": "tcn_boost_regime_v1",
                    "regime_state": "calm_mean_reversion",
                    "vol_percentile": 0.5,
                    "flow_percentile": 0.5,
                    "basis_percentile": 0.1,
                    "persistence_hours": 1.0,
                    "hysteresis_state": "neutral",
                    "quality_flag": "ok",
                }
                for row in feature_rows
            ],
        ),
    )

    training_run, model = train_microstructure_model(store, asset="BTC", horizon="1m")
    assert not training_run.is_empty()
    artifact = export_microstructure_model(
        model,
        asset="BTC",
        horizon="1m",
        output_dir=tmp_path / "models",
    )
    evaluation = evaluate_microstructure_model(store, model, asset="BTC", horizon="1m")
    exported_evaluation = evaluate_microstructure_model(
        store,
        artifact,
        asset="BTC",
        horizon="1m",
    )
    outputs, signals, _ = generate_microstructure_model_output(
        store,
        artifact,
        asset="BTC",
        horizon="1m",
    )

    assert artifact["artifact_uri"] == "db://microstructure_training_run/btc/1m/tcn_boost_fusion_v2"
    assert artifact["model_type"] == "tcn_boost_fusion_v2"
    assert "tcn_state_b64" in artifact
    assert "fusion_model_b64" in artifact
    assert not evaluation.is_empty()
    assert not exported_evaluation.is_empty()
    assert outputs.height > 0
    assert signals.height > 0


def test_read_market_events_normalizes_mixed_numeric_types(tmp_path: Path) -> None:
    live_root = tmp_path / "live"
    partition = live_root / "raw" / "market" / "date=2026-03-10"
    partition.mkdir(parents=True)
    rows = [
        {
            "event_type": "trade",
            "received_at": "2026-03-10T00:00:01Z",
            "payload": {
                "timestamp": "2026-03-10T00:00:01Z",
                "asset": "BTC",
                "venue": "BinanceSpot",
                "side": "buy",
                "trade_id": "1",
                "price": 70000,
                "size": 1,
            },
        },
        {
            "event_type": "mark",
            "received_at": "2026-03-10T00:00:02Z",
            "payload": {
                "timestamp": "2026-03-10T00:00:02Z",
                "asset": "BTC",
                "venue": "BinanceFutures",
                "mark_price": 70323.2,
                "oi_value": 12345.6,
                "last_update_id": 42,
            },
        },
    ]
    partition.joinpath("events.jsonl").write_text(
        "\n".join(json.dumps(row) for row in rows)
    )

    frame = _read_market_events(
        live_root,
        start=datetime(2026, 3, 10, 0, 0, tzinfo=timezone.utc),
        assets=("BTC",),
    )

    assert frame.height == 2
    assert frame.schema["price"] == pl.Float64
    assert frame.schema["mark_price"] == pl.Float64
    assert frame.schema["last_update_id"] == pl.Int64


def test_label_builder_uses_actual_bar_size_for_horizon_steps(tmp_path: Path) -> None:
    store = DatasetStore(tmp_path / "store")
    base = datetime(2026, 3, 10, 0, 0, tzinfo=timezone.utc)
    rows = []
    for index in range(80):
        ts = base + timedelta(seconds=5 * index)
        rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "asset": "BTC",
                "venue": "binance_spot",
                "clock": "event_time",
                "bar_size_secs": 5,
                "open": 100.0 + index,
                "high": 101.0 + index,
                "low": 99.0 + index,
                "close": 100.0 + index,
                "volume": 1.0,
                "buy_volume": 0.75,
                "sell_volume": 0.25,
                "trade_count": 1,
                "vwap": 100.0 + index,
                "microprice": 100.0 + index,
                "spread": 0.1,
                "depth_bid_5": 10.0,
                "depth_ask_5": 8.0,
                "is_gap": False,
                "quality_flag": "ok",
            }
        )
    store.write(
        DatasetName.MICROSTRUCTURE_BAR,
        _frame_for_dataset(DatasetName.MICROSTRUCTURE_BAR, rows),
    )

    labels = build_microstructure_label_series(
        store,
        base,
        base + timedelta(minutes=10),
        asset="BTC",
        horizons=("30s", "1m", "2m", "5m"),
    )

    steps = {
        row["horizon"]: row["label_horizon_steps"]
        for row in labels.select(["horizon", "label_horizon_steps"]).unique().iter_rows(named=True)
    }
    assert steps["30s"] == 6
    assert steps["1m"] == 12
    assert steps["2m"] == 24
    assert steps["5m"] == 60


def test_label_builder_marks_incompatible_bar_size(tmp_path: Path) -> None:
    store = DatasetStore(tmp_path / "store")
    base = datetime(2026, 3, 10, 0, 0, tzinfo=timezone.utc)
    rows = []
    for index in range(8):
        ts = base + timedelta(minutes=index)
        rows.append(
            {
                "ts": ts,
                "date": ts.date(),
                "asset": "BTC",
                "venue": "binance_spot",
                "clock": "event_time",
                "bar_size_secs": 60,
                "open": 100.0,
                "high": 101.0,
                "low": 99.0,
                "close": 100.0 + index,
                "volume": 1.0,
                "buy_volume": 0.6,
                "sell_volume": 0.4,
                "trade_count": 1,
                "vwap": 100.0 + index,
                "microprice": 100.0 + index,
                "spread": 0.1,
                "depth_bid_5": 10.0,
                "depth_ask_5": 9.0,
                "is_gap": False,
                "quality_flag": "ok",
            }
        )
    store.write(
        DatasetName.MICROSTRUCTURE_BAR,
        _frame_for_dataset(DatasetName.MICROSTRUCTURE_BAR, rows),
    )

    labels = build_microstructure_label_series(
        store,
        base,
        base + timedelta(minutes=10),
        asset="BTC",
        horizons=("30s",),
    )

    assert labels["quality_flag"].unique().to_list() == ["incompatible_bar_size"]
    assert labels["label_horizon_steps"].null_count() == labels.height


def test_feature_builder_computes_basis_rolling_delta_and_annualized_iv_gap(tmp_path: Path) -> None:
    store = DatasetStore(tmp_path / "store")
    base = datetime(2026, 3, 10, 0, 0, tzinfo=timezone.utc)
    rows = []
    for index in range(60):
        ts = base + timedelta(minutes=index)
        for venue, close in (("binance_spot", 100.0 + index), ("binance_futures", 101.0 + index)):
            rows.append(
                {
                    "ts": ts,
                    "date": ts.date(),
                    "asset": "BTC",
                    "venue": venue,
                    "clock": "event_time",
                    "bar_size_secs": 60,
                    "open": close,
                    "high": close + 1,
                    "low": close - 1,
                    "close": close,
                    "volume": 1.0,
                    "buy_volume": 0.75,
                    "sell_volume": 0.25,
                    "trade_count": 1,
                    "vwap": close,
                    "microprice": close,
                    "spread": 0.2,
                    "depth_bid_5": 12.0,
                    "depth_ask_5": 8.0,
                    "is_gap": False,
                    "quality_flag": "ok",
                }
            )
    store.write(
        DatasetName.MICROSTRUCTURE_BAR,
        _frame_for_dataset(DatasetName.MICROSTRUCTURE_BAR, rows),
    )
    store.write(
        DatasetName.FUNDING_RATE_SNAPSHOT,
        _frame_for_dataset(
            DatasetName.FUNDING_RATE_SNAPSHOT,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "venue": "binance_futures",
                    "underlying": "BTC",
                    "source": "funding_history",
                    "interest_1h": 0.0001,
                    "interest_8h": None,
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    store.write(
        DatasetName.SURFACE_FEATURES,
        _frame_for_dataset(
            DatasetName.SURFACE_FEATURES,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "underlying": "BTC",
                    "source": "ssvi",
                    "atm_iv_7d": 0.6,
                    "atm_iv_14d": 0.61,
                    "atm_iv_30d": 0.62,
                    "atm_iv_60d": 0.63,
                    "rr_25_7d": -0.01,
                    "rr_25_30d": -0.04,
                    "bf_25_7d": 0.01,
                    "bf_25_30d": 0.02,
                    "term_slope_7_30": 0.02,
                    "term_slope_30_60": 0.01,
                    "fit_quality": 0.01,
                    "coverage_ratio": 0.95,
                    "maturity_violations": 0,
                    "fit_validity_flag": "valid",
                    "quality_flag": "ok",
                }
            ],
        ),
    )

    features = build_microstructure_feature_series(
        store,
        base,
        base + timedelta(hours=2),
        asset="BTC",
        horizons=("1m",),
    ).sort("ts")

    latest = features.tail(1).to_dicts()[0]
    expected_basis = ((160.0 - 159.0) / 159.0) * 10_000.0
    assert latest["cum_delta_10"] == 10.0
    assert latest["cum_delta_30"] == 30.0
    assert latest["cum_delta_50"] == 50.0
    assert latest["basis_bps"] == pytest.approx(expected_basis, rel=1e-6)
    annualization = (365.0 * 24.0 * 60.0 * 60.0 / 60.0) ** 0.5
    assert latest["iv_rv_gap"] == pytest.approx(
        0.6 - (latest["realized_vol"] * annualization),
        rel=1e-6,
    )


def test_validation_split_applies_embargo_gap() -> None:
    split = _validation_split(200, label_horizon_steps=5)
    assert split is not None
    train_idx, val_idx = split
    embargo = max(SEQUENCE_LENGTH - 1, 5)
    assert int(val_idx[0]) - int(train_idx[-1]) > embargo


def test_tcn_has_full_receptive_field_depth() -> None:
    model = TcnClassifier(input_dim=12)
    assert len(model.backbone) == 6


def test_partition_reader_scans_more_than_two_days(tmp_path: Path) -> None:
    root = tmp_path / "raw"
    start = datetime(2026, 3, 8, 0, 0, tzinfo=timezone.utc)
    for offset in range(3):
        day = (start + timedelta(days=offset)).date().isoformat()
        partition = root / f"date={day}"
        partition.mkdir(parents=True)
        partition.joinpath("events.jsonl").write_text(json.dumps({"day": day}))

    lines = _read_jsonl_partitioned(root, start)
    assert len(lines) == 3


def test_market_event_reader_uses_incremental_cursor_state(tmp_path: Path) -> None:
    live_root = tmp_path / "live"
    partition = live_root / "raw" / "market" / "date=2026-03-13"
    partition.mkdir(parents=True)
    file_path = partition / "events.jsonl"
    first_row = {
        "event_type": "trade",
        "received_at": "2026-03-13T21:00:01Z",
        "payload": {
            "timestamp": "2026-03-13T21:00:01Z",
            "asset": "BTC",
            "venue": "BinanceFutures",
            "side": "buy",
            "trade_id": "1",
            "price": 70000.0,
            "size": 0.01,
        },
    }
    file_path.write_text(json.dumps(first_row) + "\n")

    start = datetime(2026, 3, 13, 20, 55, tzinfo=timezone.utc)
    cursor_state: dict[str, int] = {}

    first = _read_market_events(
        live_root,
        start=start,
        assets=("BTC",),
        cursor_state=cursor_state,
    )
    assert first.height == 1
    assert first.item(0, "trade_notional") == pytest.approx(700.0)
    assert cursor_state[str(file_path)] > 0

    second = _read_market_events(
        live_root,
        start=start,
        assets=("BTC",),
        cursor_state=cursor_state,
    )
    assert second.is_empty()

    second_row = {
        "event_type": "trade",
        "received_at": "2026-03-13T21:00:02Z",
        "payload": {
            "timestamp": "2026-03-13T21:00:02Z",
            "asset": "BTC",
            "venue": "BinanceFutures",
            "side": "sell",
            "trade_id": "2",
            "price": 70010.0,
            "size": 0.02,
        },
    }
    with file_path.open("a") as handle:
        handle.write(json.dumps(second_row) + "\n")

    third = _read_market_events(
        live_root,
        start=start,
        assets=("BTC",),
        cursor_state=cursor_state,
    )
    assert third.height == 1
    assert third.item(0, "side") == "sell"
    assert third.item(0, "price") == pytest.approx(70010.0)


def test_microstructure_api_endpoints(tmp_path: Path) -> None:
    store = DatasetStore(tmp_path / "store")
    base = datetime(2026, 3, 1, 12, tzinfo=timezone.utc)
    store.write(
        DatasetName.MICROSTRUCTURE_MODEL_OUTPUT,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_MODEL_OUTPUT,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "asset": "BTC",
                    "horizon": "1m",
                    "source": "tcn_boost_fusion",
                    "prob_down": 0.2,
                    "prob_flat": 0.3,
                    "prob_up": 0.5,
                    "expected_move_bps": 4.0,
                    "expected_edge_bps": 2.0,
                    "tradability_score": 0.3,
                    "confidence": 0.5,
                    "confidence_bucket": "medium",
                    "regime_state": "calm_mean_reversion",
                    "blocked_reason": None,
                    "model_version": "tcn_boost_fusion_v2",
                    "model_family": "fusion",
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_SIGNAL_SERIES,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_SIGNAL_SERIES,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "asset": "BTC",
                    "horizon": "1m",
                    "source": "tcn_boost_paper_signal",
                    "signal_state": "long_bias",
                    "paper_position": "long",
                    "expected_edge_bps": 1.2,
                    "cost_filter_passed": True,
                    "quality_filter_passed": True,
                    "blocked_reason": None,
                    "confidence": 0.5,
                    "tradability_score": 0.3,
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_FEATURE_SERIES,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_FEATURE_SERIES,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "asset": "BTC",
                    "horizon": "1m",
                    "source": "tcn_boost_features_v2",
                    "bar_size_secs": 60,
                    "mid_price": 50_000.0,
                    "return_1": 0.0,
                    "return_5": 0.0,
                    "realized_vol": 0.01,
                    "book_imbalance": 0.2,
                    "microprice_tilt": 0.001,
                    "order_flow_imbalance": 0.1,
                    "cumulative_delta": 5.0,
                    "cum_delta_10": 4.0,
                    "cum_delta_30": 5.0,
                    "cum_delta_50": 6.0,
                    "spread_rel": 0.0001,
                    "depth_total": 200.0,
                    "volume_delta": 2.0,
                    "microprice_gap": 0.5,
                    "ofi_mean_12": 0.0,
                    "ofi_std_12": 1.0,
                    "imbalance_mean_12": 0.2,
                    "spread_rel_mean_12": 0.0001,
                    "depth_change_1": 0.0,
                    "microprice_tilt_change_5": 0.0,
                    "basis_bps": 0.0,
                    "funding_rate": 0.0001,
                    "oi_value": None,
                    "liquidation_volume": None,
                    "iv_atm": 0.6,
                    "iv_skew_25d": -0.04,
                    "iv_rv_gap": 0.59,
                    "cross_venue_spread": 1.0,
                    "horizon_secs": 60,
                    "feature_count": 20,
                    "feature_payload": "{}",
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_REGIME_SERIES,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_REGIME_SERIES,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "asset": "BTC",
                    "source": "tcn_boost_regime_v1",
                    "regime_state": "calm_mean_reversion",
                    "vol_percentile": 0.5,
                    "flow_percentile": 0.4,
                    "basis_percentile": 0.1,
                    "persistence_hours": 2.0,
                    "hysteresis_state": "neutral",
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    store.write(
        DatasetName.MICROSTRUCTURE_TRAINING_RUN,
        _frame_for_dataset(
            DatasetName.MICROSTRUCTURE_TRAINING_RUN,
            [
                {
                    "ts": base,
                    "date": base.date(),
                    "asset": "BTC",
                    "horizon": "1m",
                    "source": "tcn_boost_fusion",
                    "model_version": "tcn_boost_fusion_v2",
                    "train_start": base - timedelta(days=30),
                    "train_end": base,
                    "split_count": 5,
                    "cv_accuracy_mean": 0.42,
                    "cv_accuracy_std": 0.03,
                    "brier_score": 0.2,
                    "calibration_error": 0.2,
                    "lift_vs_tabular": 0.03,
                    "profitable": True,
                    "artifact_path": "/tmp/model.json",
                    "feature_schema_version": 2,
                    "label_schema_version": 3,
                    "validation_embargo_bars": 32,
                    "tabular_best_iteration": 120,
                    "fusion_best_iteration": 140,
                    "quality_flag": "ok",
                }
            ],
        ),
    )
    app = create_app(settings=ApiSettings(data_root=tmp_path / "store"), store=store)
    client = TestClient(app)

    signals = client.get("/api/v1/microstructure/signals")
    latest = client.get("/api/v1/microstructure/signals/btc_microstructure_1m/latest")
    series = client.get("/api/v1/microstructure/signals/btc_microstructure_1m/series")
    features = client.get("/api/v1/microstructure/features/BTC", params={"horizon": "1m"})
    regime = client.get("/api/v1/microstructure/regime/BTC")
    health = client.get("/api/v1/microstructure/health")

    assert signals.status_code == 200
    assert latest.status_code == 200
    assert latest.json()["data"]["latest_values"]["prob_up"] == 0.5
    assert series.status_code == 200
    assert len(series.json()["data"]["points"]) == 1
    assert features.status_code == 200
    assert regime.status_code == 200
    assert health.status_code == 200
