"""期权平仓门控:USDT 口径(权利金×倍数 / 净盈亏阈值)且持续持有."""
from __future__ import annotations

import os
import unittest

from lib.options.options_close_gate_lib import (
    clear_close_gate,
    is_close_gate_passed,
    mark_close_gate_passed,
    update_close_gate,
)


class OptionsCloseGateTests(unittest.TestCase):
    def setUp(self):
        clear_close_gate()
        self._env_backup = {
            k: os.environ.get(k)
            for k in (
                "OKX_OPTIONS_CLOSE_GATE_MODE",
                "OKX_OPTIONS_CLOSE_RECYCLE_MULT",
                "OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN",
                "OKX_OPTIONS_CLOSE_RECYCLE_MULT_USDC",
                "OKX_OPTIONS_CLOSE_NET_PNL_MIN_U",
            )
        }
        for k in self._env_backup:
            os.environ.pop(k, None)

    def tearDown(self):
        clear_close_gate()
        for k, v in self._env_backup.items():
            if v is None:
                os.environ.pop(k, None)
            else:
                os.environ[k] = v

    def test_usdc_below_2x_not_ready(self):
        g = update_close_gate(
            "ETH-X",
            recycle_usdc=15.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1000.0,
        )
        self.assertFalse(g["recycle_ok"])
        self.assertFalse(g["ready"])
        self.assertIn("U(估)", g["msg"])

    def test_usdc_meets_2x_needs_hold(self):
        g1 = update_close_gate(
            "ETH-X",
            recycle_usdc=20.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1000.0,
        )
        self.assertTrue(g1["recycle_ok"])
        self.assertFalse(g1["ready"])
        self.assertAlmostEqual(g1["remain_seconds"], 120.0)

        g2 = update_close_gate(
            "ETH-X",
            recycle_usdc=21.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1120.0,
        )
        self.assertTrue(g2["ready"])

    def test_coin_premium_gate_uses_usdt_and_default_105(self):
        # 0.0384 ETH * 2500 = 96U; ×1.05 = 100.8U
        g = update_close_gate(
            "ETH-P",
            recycle_usdc=0.036,
            premium_paid=0.0384,
            premium_ccy="ETH",
            index_px=2500.0,
            now=1000.0,
        )
        self.assertFalse(g["recycle_ok"])
        self.assertAlmostEqual(g["premium_usdt"], 96.0)
        self.assertAlmostEqual(g["need_recycle_usdt"], 100.8)
        self.assertIn("U(估)", g["msg"])

        g_ok = update_close_gate(
            "ETH-P",
            recycle_usdc=0.041,
            premium_paid=0.0384,
            premium_ccy="ETH",
            index_px=2500.0,
            now=1000.0,
        )
        self.assertTrue(g_ok["recycle_ok"])
        self.assertAlmostEqual(g_ok["recycle_usdt"], 102.5)

    def test_net_pnl_gate_mode(self):
        os.environ["OKX_OPTIONS_CLOSE_GATE_MODE"] = "net_pnl"
        os.environ["OKX_OPTIONS_CLOSE_NET_PNL_MIN_U"] = "1"
        g = update_close_gate(
            "ETH-N",
            recycle_usdc=0.039,
            premium_paid=0.0384,
            premium_ccy="ETH",
            index_px=2500.0,
            now=1000.0,
        )
        self.assertTrue(g["recycle_ok"])
        self.assertAlmostEqual(g["net_pnl_usdt"], 1.5)

        g2 = update_close_gate(
            "ETH-N2",
            recycle_usdc=0.0385,
            premium_paid=0.0384,
            premium_ccy="ETH",
            index_px=2500.0,
            now=1000.0,
        )
        self.assertFalse(g2["recycle_ok"])

    def test_break_resets_timer(self):
        update_close_gate(
            "ETH-X",
            recycle_usdc=20.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1000.0,
        )
        update_close_gate(
            "ETH-X",
            recycle_usdc=21.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1100.0,
        )
        g_break = update_close_gate(
            "ETH-X",
            recycle_usdc=12.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1110.0,
        )
        self.assertFalse(g_break["recycle_ok"])
        g_again = update_close_gate(
            "ETH-X",
            recycle_usdc=22.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1111.0,
        )
        self.assertTrue(g_again["recycle_ok"])
        self.assertFalse(g_again["ready"])
        self.assertAlmostEqual(g_again["held_seconds"], 0.0)

    def test_passed_latches_after_ready(self):
        update_close_gate(
            "ETH-Y",
            recycle_usdc=20.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1000.0,
        )
        g_ready = update_close_gate(
            "ETH-Y",
            recycle_usdc=21.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1120.0,
        )
        self.assertTrue(g_ready["ready"])
        self.assertTrue(g_ready["passed"])
        self.assertTrue(is_close_gate_passed("ETH-Y"))
        g_drop = update_close_gate(
            "ETH-Y",
            recycle_usdc=5.0,
            premium_paid=10.0,
            premium_ccy="USDC",
            now=1130.0,
        )
        self.assertFalse(g_drop["recycle_ok"])
        self.assertTrue(g_drop["passed"])
        self.assertFalse(g_drop["auto_close_blocked"])

    def test_mark_passed_manual(self):
        mark_close_gate_passed("ETH-Z")
        self.assertTrue(is_close_gate_passed("ETH-Z"))


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