from __future__ import annotations

import pytest

import libs.intraday.catalyst as catalyst_mod
from libs.intraday.catalyst import (
    AttentionEventCache,
    FilingEventCache,
    fetch_attention_features_bulk,
    fetch_filing_event_features_bulk,
)
from libs.oracle_client.models import (
    EntityInfo,
    EventAttentionResponse,
    FilingEventEntry,
    FilingEventsResponse,
    NewsFeatures,
    WikiFeatures,
)


def test_filing_event_cache_roundtrip(tmp_path) -> None:
    cache = FilingEventCache(str(tmp_path))
    cache.put(
        "ABC",
        "2026-01-01",
        "2026-03-31",
        [
            {
                "ticker": "ABC",
                "filing_date": "2026-02-10",
                "accession_number": "1",
                "event_type": "other_material_event",
                "item_number": "8.01",
                "form_type": "8-K",
                "title": "Material event",
            }
        ],
    )

    hit = cache.get("ABC", "2026-01-02", "2026-03-01")
    miss = cache.get("ABC", "2025-12-31", "2026-03-01")

    assert hit is not None and hit[0]["event_type"] == "other_material_event"
    assert miss is None


@pytest.mark.asyncio
async def test_fetch_filing_event_features_bulk_uses_cache_after_first_hit(tmp_path, monkeypatch) -> None:
    cache = FilingEventCache(str(tmp_path))
    calls = {"count": 0}

    async def fake_get_events(self, ticker, start_date=None, end_date=None):
        calls["count"] += 1
        return FilingEventsResponse(
            ticker=ticker,
            events=[
                FilingEventEntry(
                    id="evt-1",
                    ticker=ticker,
                    accession_number="acc-1",
                    form_type="8-K",
                    filing_date="2026-02-10",
                    item_number="8.01",
                    event_type="other_material_event",
                    title="Material event",
                )
            ],
            total_count=1,
        )

    monkeypatch.setattr(catalyst_mod.FilingsService, "get_filing_events", fake_get_events)

    first = await fetch_filing_event_features_bulk(
        ["ABC"],
        "2026-01-01",
        "2026-03-31",
        client=object(),  # patched method ignores the client
        cache=cache,
        concurrency=1,
    )
    second = await fetch_filing_event_features_bulk(
        ["ABC"],
        "2026-01-01",
        "2026-03-31",
        client=object(),
        cache=cache,
        concurrency=1,
    )

    assert first["ABC"]["2026-02-10"]["event_flag"] is True
    assert first["ABC"]["2026-02-10"]["event_score"] >= 1.0
    assert second == first
    assert calls["count"] == 1


def test_attention_event_cache_roundtrip(tmp_path) -> None:
    cache = AttentionEventCache(str(tmp_path))
    cache.put(
        "ABC",
        "2026-02-10",
        {
            "attention_wiki_spike_10d": 2.3,
            "attention_wiki_zscore_20d": 3.1,
            "attention_article_count_3d": 5,
            "attention_us_article_count_3d": 3,
            "attention_resolver_confidence": 0.95,
        },
    )

    hit = cache.get("ABC", "2026-02-10")
    miss = cache.get("ABC", "2026-02-11")

    assert hit is not None and hit["attention_article_count_3d"] == 5
    assert miss is None


@pytest.mark.asyncio
async def test_fetch_attention_features_bulk_uses_cache_after_first_hit(tmp_path, monkeypatch) -> None:
    cache = AttentionEventCache(str(tmp_path))
    calls = {"count": 0}

    async def fake_get_attention(self, ticker, event_date):
        calls["count"] += 1
        return EventAttentionResponse(
            ticker=ticker,
            event_date=event_date,
            entity=EntityInfo(
                ticker=ticker,
                canonical_name=ticker,
                resolver_confidence=0.91,
            ),
            wiki=WikiFeatures(spike_10d=2.8, zscore_20d=3.4),
            news=NewsFeatures(article_count_3d=6, us_article_count_3d=4),
            metadata={},
        )

    monkeypatch.setattr(catalyst_mod.AttentionService, "get_event_attention", fake_get_attention)

    first = await fetch_attention_features_bulk(
        [("ABC", "2026-02-10")],
        client=object(),
        cache=cache,
        concurrency=1,
    )
    second = await fetch_attention_features_bulk(
        [("ABC", "2026-02-10")],
        client=object(),
        cache=cache,
        concurrency=1,
    )

    assert first["ABC"]["2026-02-10"]["attention_wiki_spike_10d"] == 2.8
    assert first["ABC"]["2026-02-10"]["attention_us_article_count_3d"] == 4
    assert second == first
    assert calls["count"] == 1
