from __future__ import annotations

import unittest

from backend.features.market.charts import ChartDataError, EastmoneyChartClient
from server import DashboardService


class FakeChartClient(EastmoneyChartClient):
    def __init__(self) -> None:
        super().__init__(cache_ttl_seconds=20)
        self.requests: list[tuple[str, dict[str, str]]] = []

    def _request_json(self, url, params, referer):
        self.requests.append((url, params))
        if "trends2" in url:
            return {
                "data": {
                    "code": params["secid"].split(".", 1)[1],
                    "name": "测试行情",
                    "preClose": 10.0,
                    "trends": [
                        "2026-07-24 09:30,10.10,10.20,10.30,10.00,100,1020.00,10.200",
                        "2026-07-24 09:31,10.20,10.15,10.25,10.10,80,812.00,10.178",
                    ],
                }
            }
        return {
            "data": {
                "diff": [
                    {"f12": "BK0474", "f14": "保险Ⅱ"},
                    {"f12": "BK1040", "f14": "中药Ⅱ"},
                ]
            }
        }


class ChartDataProviderTests(unittest.TestCase):
    def setUp(self) -> None:
        EastmoneyChartClient._cache.clear()
        EastmoneyChartClient._board_catalog.clear()
        EastmoneyChartClient._board_catalog_at = 0
        self.client = FakeChartClient()

    def test_stock_intraday_maps_market_and_parses_points(self):
        payload = self.client.stock_intraday("601318")

        self.assertEqual(self.client.requests[0][1]["secid"], "1.601318")
        self.assertEqual(payload["trade_date"], "2026-07-24")
        self.assertEqual(payload["points"][0]["time"], "09:30")
        self.assertEqual(payload["points"][0]["average"], 10.2)

    def test_short_cache_avoids_duplicate_hover_requests(self):
        self.client.stock_intraday("002141")
        self.client.stock_intraday("002141")

        trend_requests = [item for item in self.client.requests if "trends2" in item[0]]
        self.assertEqual(len(trend_requests), 1)

    def test_index_and_board_use_the_same_chart_shape(self):
        index = self.client.index_intraday("000001.SH")
        board = self.client.board_intraday("BK0474")

        self.assertEqual(index["points"][1]["close"], 10.15)
        self.assertEqual(board["points"][1]["volume"], 80.0)
        secids = [params["secid"] for url, params in self.client.requests if "trends2" in url]
        self.assertIn("1.000001", secids)
        self.assertIn("90.BK0474", secids)

    def test_invalid_identifier_is_rejected(self):
        with self.assertRaises(ChartDataError):
            self.client.stock_intraday("abc")


class ChartServiceStub:
    @staticmethod
    def _payload(code: str, name: str):
        return {
            "code": code,
            "name": name,
            "trade_date": "2026-07-24",
            "previous_close": 10,
            "points": [{"date": "2026-07-24", "time": "09:30", "close": 10.1}],
        }

    def stock_intraday(self, code):
        return self._payload(code, "测试股票")

    def index_intraday(self, identifier):
        return self._payload(identifier, "上证指数")

    def board_intraday(self, identifier, name=""):
        return self._payload("BK0474", name)


class ChartDirectoryStub:
    @staticmethod
    def get_data_snapshot(kind, cache_key):
        if (kind, cache_key) != ("search_directory", "ths"):
            return None
        return {
            "schema_version": 2,
            "items": [
                {"id": "881107.TI", "name": "保险", "type": "sector"},
                {"id": "885728.TI", "name": "人工智能", "type": "theme"},
            ],
        }


class IntradayChartServiceTests(unittest.TestCase):
    def setUp(self):
        self.service = DashboardService.__new__(DashboardService)
        self.service.chart_data = ChartServiceStub()
        self.service.database = ChartDirectoryStub()

    def test_stock_index_sector_and_theme_share_display_only_contract(self):
        cases = (
            ("stock", "601318"),
            ("index", "000001.SH"),
            ("sector", "881107.TI"),
            ("theme", "885728.TI"),
        )
        for entity_type, identifier in cases:
            with self.subTest(entity_type=entity_type):
                payload = self.service.get_intraday_chart(entity_type, identifier)
                self.assertEqual(payload["entity"]["type"], entity_type)
                self.assertEqual(payload["meta"]["trade_date"], "2026-07-24")
                self.assertEqual(len(payload["points"]), 1)
                self.assertNotIn("source", payload["meta"])


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