from __future__ import annotations

import unittest

from datahub.normalize import (
    AMOUNT_THOUSAND_YUAN,
    AMOUNT_WAN_YUAN,
    VOLUME_LOT,
    apply_qfq,
    normalize_auction,
    normalize_daily,
    normalize_index_daily,
    normalize_moneyflow,
    normalize_valuation,
    review_daily_to_canonical,
)
from tests.fixtures import RAW


class NormalizeTests(unittest.TestCase):
    def test_daily_matches_architecture_and_review_native_conversion(self) -> None:
        raw = RAW["daily"][0]
        hub = normalize_daily(raw, adj_factor=1.1)
        # review stores Tushare native units; canonical = review * factor
        review_native = dict(raw)
        converted = review_daily_to_canonical(review_native)
        self.assertEqual(hub["amount"], converted["amount"])
        self.assertEqual(hub["amount"], raw["amount"] * AMOUNT_THOUSAND_YUAN)
        self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)
        self.assertEqual(hub["close"], 10.2)
        self.assertEqual(hub["adj_factor"], 1.1)
        self.assertEqual(hub["ts_code"], "600000.SH")

    def test_moneyflow_wan_to_yuan(self) -> None:
        raw = RAW["moneyflow"][0]
        hub = normalize_moneyflow(raw)
        self.assertEqual(hub["net_mf_amount"], raw["net_mf_amount"] * AMOUNT_WAN_YUAN)
        self.assertEqual(hub["buy_lg_amount"], 30 * AMOUNT_WAN_YUAN)

    def test_valuation_mv_wan_to_yuan(self) -> None:
        raw = RAW["daily_basic"][0]
        hub = normalize_valuation(raw)
        self.assertEqual(hub["total_mv"], 1000 * AMOUNT_WAN_YUAN)
        self.assertEqual(hub["circ_mv"], 800 * AMOUNT_WAN_YUAN)

    def test_index_daily_amount_thousand_yuan(self) -> None:
        raw = RAW["index_daily"][0]
        hub = normalize_index_daily(raw)
        self.assertEqual(hub["amount"], raw["amount"] * AMOUNT_THOUSAND_YUAN)
        self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)

    def test_auction_amount_already_yuan(self) -> None:
        raw = RAW["stk_auction"][0]
        hub = normalize_auction(raw)
        self.assertEqual(hub["amount"], raw["amount"])
        self.assertEqual(hub["volume"], raw["vol"] * VOLUME_LOT)

    def test_field_diff_against_review_native_is_explained(self) -> None:
        """Golden: every non-zero diff vs review-native daily is a documented unit factor."""
        raw = RAW["daily"][0]
        hub = normalize_daily(raw)
        diffs = {}
        for key in ("open", "high", "low", "close", "pct_chg"):
            if hub[key] != raw[key]:
                diffs[key] = (raw[key], hub[key])
        self.assertEqual(diffs, {})
        self.assertNotEqual(hub["amount"], raw["amount"])
        self.assertEqual(hub["amount"] / raw["amount"], AMOUNT_THOUSAND_YUAN)
        self.assertEqual(hub["volume"] / raw["vol"], VOLUME_LOT)

    def test_qfq_formula(self) -> None:
        self.assertEqual(apply_qfq(10.0, 1.1, 2.2), 5.0)
        none_price = apply_qfq(None, 1.1, 2.2)
        self.assertIsNone(none_price)


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