"""Tests for the two-compartment phosphate kinetics model."""

import pytest

from nephrosim.models.phosphate_kinetics import PhosphateKineticsModel


@pytest.fixture
def phos_model():
    return PhosphateKineticsModel()


class TestPhosphateKineticsModel:
    def test_reset(self, phos_model):
        state = phos_model.reset(5.5, 5.0)
        assert abs(state[0] - 5.5) < 0.01
        assert abs(state[1] - 5.0) < 0.01

    def test_phosphate_drops_during_dialysis(self, phos_model):
        phos_model.reset(6.0, 6.0)
        result = phos_model.step_dialysis(350, 500, dt=60.0)
        assert result["p_ecf"] < 6.0

    def test_phosphate_rises_interdialytic(self, phos_model):
        phos_model.reset(3.5, 3.5)
        result = phos_model.step_interdialytic(dt_hours=24.0)
        assert result["p_ecf"] > 3.5

    def test_binder_reduces_phosphate_rise(self, phos_model):
        phos_model.reset(4.0, 4.0)
        r1 = phos_model.step_interdialytic(binder_dose_mg=0, dt_hours=24.0)
        phos_model.reset(4.0, 4.0)
        r2 = phos_model.step_interdialytic(binder_dose_mg=1500, dt_hours=24.0)
        assert r2["p_ecf"] < r1["p_ecf"]

    def test_calcium_phosphate_product(self, phos_model):
        phos_model.reset(5.0, 5.0)
        result = phos_model.step_dialysis(350, 500, dt=1.0)
        assert abs(result["calcium_phosphate_product"] - result["p_ecf"] * 9.5) < 0.1

    def test_state_stays_in_bounds(self, phos_model):
        phos_model.reset(10.0, 10.0)
        for _ in range(100):
            result = phos_model.step_dialysis(500, 800, dt=10.0)
        assert result["p_ecf"] >= 0.5
        assert result["p_ecf"] <= 15.0

    def test_clearance_positive(self, phos_model):
        phos_model.reset(5.5, 5.5)
        result = phos_model.step_dialysis(350, 500, dt=1.0)
        assert result["clearance"] > 0

    def test_weekly_cycle(self, phos_model):
        """Simulate a full week: MWF dialysis, daily binder."""
        phos_model.reset(6.0, 5.5)
        for day in range(7):
            is_dialysis_day = day in [0, 2, 4]  # MWF
            if is_dialysis_day:
                phos_model.step_dialysis(350, 500, binder_dose_mg=1000, dt=240)
            phos_model.step_interdialytic(binder_dose_mg=1000, dt_hours=20 if is_dialysis_day else 24)
        assert 2.0 < phos_model.state[0] < 8.0
