"""Канон доходных строк: раскладка CRM и финмодели. Всё без сети."""
import income_lines as il


def test_canon_has_nine_lines_with_unique_slugs():
    slugs = [l.slug for l in il.LINES]
    assert slugs == ["uroki", "gruppy", "hor", "arenda", "iventy", "cover", "b2b",
                     "podpiska", "prochee"]
    assert len(set(slugs)) == len(slugs)


def test_cover_session_maps_to_crm_syomki_direction():
    # грабля 31.07.2026: направление CRM «Съёмки» — это Cover session,
    # а «Мероприятия внешние» из финмодели к нему отношения не имеют
    assert il.by_slug("cover").crm_dirs == ["Съёмки"]
    assert "Съёмки" not in il.by_slug("prochee").crm_dirs


def test_b2b_line_sums_three_model_rows():
    assert il.by_slug("b2b").model_rows == [14, 15, 16]


def test_prochee_collects_model_rows_without_crm_direction():
    # мероприятия внешние (8) и мерч (11); онлайн-подписка живёт своей строкой
    assert il.by_slug("prochee").model_rows == [8, 11]
    assert il.by_slug("prochee").crm_dirs == []


def test_podpiska_exists_with_no_crm_direction_yet():
    """Клуб не запущен, направления в CRM нет — строка заведена заранее с нулевым
    фактом, чтобы при запуске не перестраивать канон, планки и два листа."""
    l = il.by_slug("podpiska")
    assert l.crm_dirs == [] and l.model_rows == [7]
    assert il.crm_fact_for(l, {"1-1": 100.0}, other=50.0) == 0.0


def test_income_with_other_returns_directions_and_other_total(monkeypatch):
    import margins
    fake = {"07.2026": {"1-1": 100.0, "Хор": 50.0,
                        "__crm_other__": {"Мерч": 7.0, "Мероприятия внешние": 3.0},
                        "__income_detail__": {}}}
    monkeypatch.setattr(margins, "_collect_income", lambda *a, **k: fake)
    monkeypatch.setattr(margins, "alfa_login", lambda: "tok")
    monkeypatch.setattr(margins, "_alfa_pay_items", lambda t: {})
    dirs, other = margins.income_with_other("07.2026")
    assert dirs["1-1"] == 100.0
    assert other == 10.0            # мерч + внешние мероприятия


def test_crm_fact_from_month_data_matches_crm_fact(monkeypatch):
    """Находка #4 финального ревью: crm_fact_from_month_data (данные уже посчитаны
    margins.income_all_months одним проходом) должна давать тот же результат, что
    crm_fact (отдельный запрос на месяц) — иначе смена источника незаметно поехала бы
    в числах листа «План-факт»."""
    import margins
    month_data = {"1-1": 100.0, "Хор": 50.0,
                  "__crm_other__": {"Мерч": 7.0, "Мероприятия внешние": 3.0},
                  "__income_detail__": {}}
    monkeypatch.setattr(margins, "income_with_other",
                        lambda mm, token=None, pay_items=None: (
                            {d: month_data.get(d, 0.0) for d in margins.DIRECTIONS},
                            sum(month_data.get("__crm_other__", {}).values())))
    via_month_data = il.crm_fact_from_month_data(month_data)
    via_crm_fact = il.crm_fact("07.2026")
    assert via_month_data == via_crm_fact
    assert via_month_data["hor"] == 50.0
    assert via_month_data["prochee"] == 10.0   # мерч + внешние мероприятия


def test_plan_income_accepts_canon_slugs():
    import plan_income
    assert set(plan_income.LINES) == {l.slug for l in il.LINES}
    assert plan_income.LINES["uroki"][1] == il.CAT_B2C
    assert plan_income.LINES["b2b"][1] == il.CAT_B2B


def test_report_income_lines_is_canon_alias():
    import report
    assert [l.slug for l in report.INCOME_LINES] == [l.slug for l in il.LINES]


def test_build_income_expect_gives_prochee_the_other_bucket():
    """Находка #3 финального ревью: «Прочее» (crm_dirs=[]) раньше всегда получало факт 0,
    потому что report.py суммировал по l.crm_dirs напрямую вместо il.crm_fact_for.
    Теперь «Прочее» = crm_other, «Онлайн-подписка» (тоже пустой crm_dirs) — по-прежнему 0."""
    import report
    pinc = {"prochee": 20_000.0}
    crm = {"1-1": 100.0, "Хор": 50.0}
    crm_other = 15_000.0
    rows = {r["name"]: r for r in report.build_income_expect(pinc, crm, crm_other)}
    assert rows["Прочее"]["got"] == 15_000.0
    assert rows["Прочее"]["wait"] == 5_000.0
    assert rows["Онлайн-подписка"]["got"] == 0.0
    assert rows["1-1"]["got"] == 100.0


def test_income_block_adds_missing_crm_row(monkeypatch):
    """Факт Финтабло и сумма CRM не сходятся (июль 2026: 4 305 513 против 4 157 029) —
    расхождение показываем строкой, а не прячем."""
    import plan_fact as pf
    monkeypatch.setattr(il, "crm_fact", lambda mm, token=None: {"uroki": 4_157_029.0})
    monkeypatch.setattr(il, "plan_from_fintablo", lambda mm, ai=None: {"uroki": 4_000_000.0})
    rows = dict(pf.income_block("07.2026", [], 4_305_513.0))
    assert rows["мимо CRM"] == 148_484.0
