"""
Known-case tests for the Accounting Quality / Red Flags module (StockLab overhaul, Part 8).
Plain-function style — see test_metrics_known_cases.py for why.
"""
from __future__ import annotations

from datetime import date

from app.engines.quality.accounting import assess_accounting_quality
from app.engines.types import FinancialSnapshot, LineItems, MarketCapBucket


def _li(period_end: str, **kwargs) -> LineItems:
    defaults = dict(
        security_id="TEST", period_end=date.fromisoformat(period_end), period_type="FY",
        filing_date=date.fromisoformat(period_end), currency="USD",
    )
    defaults.update(kwargs)
    return LineItems(**defaults)


def _snapshot(current: LineItems, history: list[LineItems]) -> FinancialSnapshot:
    return FinancialSnapshot(
        security_id="TEST", industry_id="TEST_IND", sector_id="DEFAULT",
        market_cap_bucket=MarketCapBucket.LARGE, calculation_date=current.period_end,
        current=current, history=history,
    )


def test_clean_company_raises_no_flags():
    cur = _li("2025-12-31", revenue=1100, net_income=150, operating_cash_flow=170,
              capital_expenditure=40, receivables=110, inventory=90, total_debt=210,
              diluted_shares=101, goodwill=50, total_assets=1000, operating_income=200)
    h = [_li("2024-12-31", revenue=1000, net_income=140, operating_cash_flow=160,
             receivables=100, inventory=85, total_debt=200, diluted_shares=100, operating_income=190)]
    report = assess_accounting_quality(_snapshot(cur, h))
    assert report.flags == []
    assert "cash_flow_quality" in report.checks_run


def test_earnings_quality_flag_when_ocf_trails_net_income():
    cur = _li("2025-12-31", net_income=100, operating_cash_flow=30)
    report = assess_accounting_quality(_snapshot(cur, []))
    keys = [f.key for f in report.flags]
    assert "cash_flow_quality" in keys
    flag = next(f for f in report.flags if f.key == "cash_flow_quality")
    assert flag.severity == "HIGH"  # 30/100 = 0.30 < 0.4 threshold


def test_receivables_growth_outpacing_revenue_flagged():
    cur = _li("2025-12-31", revenue=1100, receivables=180)  # revenue +10%, receivables +80%
    h = [_li("2024-12-31", revenue=1000, receivables=100)]
    report = assess_accounting_quality(_snapshot(cur, h))
    keys = [f.key for f in report.flags]
    assert "receivables_vs_revenue_growth" in keys


def test_goodwill_concentration_flag():
    cur = _li("2025-12-31", goodwill=600, total_assets=1000)
    report = assess_accounting_quality(_snapshot(cur, []))
    flag = next(f for f in report.flags if f.key == "goodwill_concentration")
    assert flag.severity == "HIGH"  # 60% > 50% threshold


def test_share_dilution_flag():
    cur = _li("2025-12-31", diluted_shares=112)
    h = [_li("2024-12-31", diluted_shares=100)]
    report = assess_accounting_quality(_snapshot(cur, h))
    flag = next(f for f in report.flags if f.key == "share_dilution")
    assert flag.severity == "HIGH"  # 12% > 10%


def test_insufficient_data_is_skipped_not_silently_passed():
    cur = _li("2025-12-31")  # nothing populated
    report = assess_accounting_quality(_snapshot(cur, []))
    assert report.flags == []
    assert "cash_flow_quality" in report.checks_skipped_insufficient_data
    assert "goodwill_concentration" in report.checks_skipped_insufficient_data


def test_remaining_unimplemented_checks_are_declared_not_silently_dropped():
    """UPDATED (Part A8). This test previously asserted that "one_off_items" and
    "acquisition_dependence" were declared NOT IMPLEMENTED. Both are now implemented as checks #9
    and #10 (under names that describe what they actually measure), so that assertion was changed
    rather than deleted — what it protects is the invariant that anything NOT implemented must be
    declared, and that invariant still has real subjects."""
    report = assess_accounting_quality(_snapshot(_li("2025-12-31"), []))
    assert any("itemized_special_charges" in c for c in report.checks_not_implemented)
    assert any("cash_paid_for_acquisitions" in c for c in report.checks_not_implemented)
    assert any("stock_based_compensation_burden" in c for c in report.checks_not_implemented)
    # every declared-not-implemented entry must carry a reason, not just a name
    assert all(len(c) > 40 and ("—" in c or "-" in c) for c in report.checks_not_implemented)
    # and the two new checks must be genuinely run, not quietly moved to the not-implemented list
    assert "non_operating_earnings_reliance" in report.checks_run
    assert "acquisition_driven_growth" in report.checks_run


# --- Part A8: check #9, non-operating earnings reliance ---


def test_non_operating_earnings_reliance_flagged_when_residual_dominates():
    """Operating income 40, interest expense 10 -> operating contribution 30. Pre-tax income 100
    means 70 of pre-tax profit (70%) came from below the operating line."""
    cur = _li("2025-12-31", operating_income=40, interest_expense=10, pretax_income=100)
    report = assess_accounting_quality(_snapshot(cur, []))
    flag = next(f for f in report.flags if f.key == "non_operating_earnings_reliance")
    assert flag.severity == "HIGH"
    assert flag.evidence["non_operating_residual"] == 70
    assert abs(flag.evidence["share_of_pretax"] - 0.70) < 1e-9


def test_non_operating_earnings_reliance_medium_severity_band():
    """Residual 35 on pre-tax 100 = 35% -> above the 25% threshold, below the 50% HIGH band."""
    cur = _li("2025-12-31", operating_income=60, interest_expense=5, pretax_income=100)
    report = assess_accounting_quality(_snapshot(cur, []))
    flag = next(f for f in report.flags if f.key == "non_operating_earnings_reliance")
    assert flag.severity == "MEDIUM"
    assert flag.evidence["non_operating_residual"] == 45  # 100 - 60 + 5


def test_non_operating_earnings_reliance_not_flagged_for_clean_operating_profit():
    """Operating income 100, interest 8, pre-tax 92 -> residual exactly 0."""
    cur = _li("2025-12-31", operating_income=100, interest_expense=8, pretax_income=92)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert not any(f.key == "non_operating_earnings_reliance" for f in report.flags)


def test_non_operating_earnings_reliance_flags_large_charge_not_just_gain():
    """A big one-off CHARGE is as much a quality signal as a big one-off gain: operating income
    100, interest 0, pre-tax 20 -> a -80 residual, 400% of pre-tax income."""
    cur = _li("2025-12-31", operating_income=100, interest_expense=0, pretax_income=20)
    report = assess_accounting_quality(_snapshot(cur, []))
    flag = next(f for f in report.flags if f.key == "non_operating_earnings_reliance")
    assert flag.severity == "HIGH"
    assert flag.evidence["non_operating_residual"] == -80
    assert "charge" in flag.description


def test_non_operating_earnings_reliance_skipped_when_pretax_missing():
    cur = _li("2025-12-31", operating_income=100)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert "non_operating_earnings_reliance" in report.checks_skipped_insufficient_data
    assert not any(f.key == "non_operating_earnings_reliance" for f in report.flags)


def test_non_operating_earnings_reliance_skipped_when_pretax_is_zero():
    """Guard against ZeroDivisionError / a meaningless 100%-of-zero ratio."""
    cur = _li("2025-12-31", operating_income=100, pretax_income=0)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert "non_operating_earnings_reliance" in report.checks_skipped_insufficient_data


def test_non_operating_earnings_reliance_materiality_floor_suppresses_noise():
    """Residual is 50% of pre-tax income but only 0.1% of revenue — a rounding error at the
    company's scale, not an earnings-quality signal. Must not flag."""
    cur = _li("2025-12-31", revenue=100_000, operating_income=100, interest_expense=0,
              pretax_income=200)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert not any(f.key == "non_operating_earnings_reliance" for f in report.flags)


def test_non_operating_earnings_reliance_still_flags_when_material_against_revenue():
    """Same 50% share, but now the residual is 10% of revenue — a real signal, must still flag."""
    cur = _li("2025-12-31", revenue=1_000, operating_income=100, interest_expense=0,
              pretax_income=200)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert any(f.key == "non_operating_earnings_reliance" for f in report.flags)


def test_non_operating_earnings_reliance_applies_without_revenue():
    """Revenue missing -> the floor cannot be evaluated, so it must not silently suppress the
    check (fail open on the flag, not closed)."""
    cur = _li("2025-12-31", operating_income=40, interest_expense=10, pretax_income=100)
    report = assess_accounting_quality(_snapshot(cur, []))
    assert any(f.key == "non_operating_earnings_reliance" for f in report.flags)


# --- Part A8: check #10, acquisition-driven growth ---


def test_acquisition_driven_growth_flagged_on_material_goodwill_jump():
    """Goodwill 100 -> 220 (+120) against prior-year total assets of 1000 = 12% intensity, with
    revenue up 30% -> HIGH (the revenue-growth clause)."""
    cur = _li("2025-12-31", goodwill=220, total_assets=1400, revenue=1300)
    h = [_li("2024-12-31", goodwill=100, total_assets=1000, revenue=1000)]
    report = assess_accounting_quality(_snapshot(cur, h))
    flag = next(f for f in report.flags if f.key == "acquisition_driven_growth")
    assert flag.severity == "HIGH"
    assert flag.evidence["goodwill_delta"] == 120
    assert abs(flag.evidence["goodwill_delta_over_prior_assets"] - 0.12) < 1e-9
    assert "unlikely to be wholly organic" in flag.description


def test_acquisition_driven_growth_medium_when_spend_is_material_but_growth_is_modest():
    """8% intensity, revenue +6% -> above the 5% threshold, below both HIGH triggers."""
    cur = _li("2025-12-31", goodwill=180, total_assets=1200, revenue=1060)
    h = [_li("2024-12-31", goodwill=100, total_assets=1000, revenue=1000)]
    report = assess_accounting_quality(_snapshot(cur, h))
    flag = next(f for f in report.flags if f.key == "acquisition_driven_growth")
    assert flag.severity == "MEDIUM"


def test_acquisition_driven_growth_notes_spend_without_growth():
    """Material goodwill added, revenue flat — arguably the worse case, and the description must
    say so rather than reusing the 'not organic' wording."""
    cur = _li("2025-12-31", goodwill=180, total_assets=1200, revenue=1000)
    h = [_li("2024-12-31", goodwill=100, total_assets=1000, revenue=1000)]
    report = assess_accounting_quality(_snapshot(cur, h))
    flag = next(f for f in report.flags if f.key == "acquisition_driven_growth")
    assert "did not grow materially" in flag.description


def test_acquisition_driven_growth_not_flagged_for_immaterial_goodwill_change():
    """+20 goodwill on 1000 prior assets = 2%, below the 5% threshold."""
    cur = _li("2025-12-31", goodwill=120, total_assets=1050, revenue=1050)
    h = [_li("2024-12-31", goodwill=100, total_assets=1000, revenue=1000)]
    report = assess_accounting_quality(_snapshot(cur, h))
    assert not any(f.key == "acquisition_driven_growth" for f in report.flags)


def test_acquisition_driven_growth_not_flagged_when_goodwill_falls():
    """A goodwill impairment is a real signal, but it is NOT this check's signal — check #7
    (goodwill_concentration) and #8 cover that side. A negative delta must not flag here."""
    cur = _li("2025-12-31", goodwill=60, total_assets=950, revenue=1000)
    h = [_li("2024-12-31", goodwill=100, total_assets=1000, revenue=1000)]
    report = assess_accounting_quality(_snapshot(cur, h))
    assert not any(f.key == "acquisition_driven_growth" for f in report.flags)


def test_acquisition_driven_growth_skipped_without_history():
    report = assess_accounting_quality(_snapshot(_li("2025-12-31", goodwill=100), []))
    assert "acquisition_driven_growth" in report.checks_skipped_insufficient_data


ALL_TESTS = [obj for name, obj in list(globals().items()) if name.startswith("test_") and callable(obj)]

if __name__ == "__main__":
    passed, failed = 0, []
    for fn in ALL_TESTS:
        try:
            fn()
            passed += 1
            print(f"PASS  {fn.__name__}")
        except AssertionError as e:
            failed.append(fn.__name__)
            print(f"FAIL  {fn.__name__}: {e}")
    print(f"\n{passed}/{len(ALL_TESTS)} passed")
    if failed:
        raise SystemExit(1)
