from __future__ import annotations

import copy
import unittest

from server import DashboardService


class SnapshotDatabase:
    def __init__(self, snapshot, latest=None):
        self.snapshot = snapshot
        self.latest = latest
        self.aliases = {}

    def get_snapshot(self, _trade_date):
        return copy.deepcopy(self.snapshot)

    def reason_overrides(self, _trade_date):
        return {}

    def get_data_snapshot(self, kind, cache_key):
        return copy.deepcopy(self.aliases.get((kind, cache_key)))

    def save_data_snapshot(self, kind, cache_key, _source, payload):
        self.aliases[(kind, cache_key)] = copy.deepcopy(payload)

    def save_snapshot(self, _trade_date, _source, payload):
        self.snapshot = copy.deepcopy(payload)

    def get_latest_real_snapshot(self, _trade_date, strictly_before=False):
        return copy.deepcopy(self.latest)


class DashboardCacheTests(unittest.TestCase):
    def service(self, snapshot):
        service = object.__new__(DashboardService)
        service.database = SnapshotDatabase(snapshot)
        return service

    def test_cached_dashboard_skips_sentiment_rebuild_when_fields_are_complete(self):
        snapshot = {
            "meta": {"source": "tushare", "trade_date": "2026-07-22"},
            "overview": {
                "sentiment_score": 32,
                "sentiment_label": "weak",
                "sentiment_phase": "retreat",
                "sentiment_direction": "cooling",
                "sentiment_components": {},
                "sentiment_engine_version": 2,
            },
        }
        service = self.service(snapshot)
        service._enrich_dashboard_sentiment = lambda *_args: self.fail(
            "complete cached sentiment must not be rebuilt"
        )

        payload = service.get_dashboard("2026-07-22")

        self.assertTrue(payload["meta"]["cached"])
        self.assertEqual(payload["overview"]["sentiment_score"], 32)

    def test_cached_dashboard_rebuilds_legacy_snapshot_missing_sentiment(self):
        snapshot = {
            "meta": {"source": "tushare", "trade_date": "2026-07-22"},
            "overview": {"limit_up_count": 20},
        }
        service = self.service(snapshot)
        calls = []

        def enrich(payload, trade_date):
            calls.append(trade_date)
            payload["overview"].update({
                "sentiment_score": 20,
                "sentiment_label": "weak",
                "sentiment_phase": "ice",
                "sentiment_direction": "cooling",
                "sentiment_components": {},
                "sentiment_engine_version": 2,
            })
            return payload

        service._enrich_dashboard_sentiment = enrich

        payload = service.get_dashboard("2026-07-22")

        self.assertEqual(calls, ["20260722"])
        self.assertEqual(payload["overview"]["sentiment_phase"], "ice")

    def test_weekend_dashboard_reuses_latest_close_without_external_sync(self):
        latest = {
            "meta": {"source": "tushare", "trade_date": "2026-07-24"},
            "overview": {
                "sentiment_score": 32,
                "sentiment_label": "weak",
                "sentiment_phase": "retreat",
                "sentiment_direction": "cooling",
                "sentiment_components": {},
            },
        }
        service = object.__new__(DashboardService)
        service.database = SnapshotDatabase(None, latest)
        service.sync_dashboard = lambda *_args: self.fail(
            "weekend refresh must not call the external synchronization path"
        )

        first = service.get_dashboard("2026-07-25")
        service.database.latest = None
        second = service.get_dashboard("2026-07-25")

        self.assertTrue(first["meta"]["carried_forward"])
        self.assertEqual(first["meta"]["trade_date"], "2026-07-24")
        self.assertEqual(second["meta"]["requested_date"], "2026-07-25")


if __name__ == "__main__":
    unittest.main()
