"""OKX 期权持仓笔数上限."""

import os
import unittest
from unittest.mock import patch

from lib.options.options_position_limit_lib import (
    count_live_option_positions,
    option_position_limit_block_msg,
    options_max_active_positions,
)


class OptionsPositionLimitTests(unittest.TestCase):
    def test_default_unlimited(self):
        with patch.dict(os.environ, {}, clear=False):
            os.environ.pop("OKX_OPTIONS_MAX_ACTIVE_POSITIONS", None)
            self.assertEqual(options_max_active_positions(), 0)

    def test_parse_max(self):
        with patch.dict(os.environ, {"OKX_OPTIONS_MAX_ACTIVE_POSITIONS": "2"}):
            self.assertEqual(options_max_active_positions(), 2)

    def test_count_live(self):
        rows = [{"instId": "A", "pos": "1"}, {"instId": "B", "pos": "0"}, {"instId": "C", "pos": "-2"}]
        self.assertEqual(count_live_option_positions(rows), 2)

    def test_block_when_at_limit(self):
        rows = [{"instId": "ETH-C", "pos": "1"}, {"instId": "ETH-P", "pos": "2"}]
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_id="ETH-NEW",
            max_active=2,
            fetch_positions=lambda _ex: rows,
        )
        self.assertIsNotNone(msg)
        self.assertIn("上限", msg or "")

    def test_allow_add_to_existing(self):
        rows = [{"instId": "ETH-C", "pos": "1"}, {"instId": "ETH-P", "pos": "2"}]
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_id="ETH-C",
            max_active=2,
            fetch_positions=lambda _ex: rows,
        )
        self.assertIsNone(msg)

    def test_allow_under_limit(self):
        rows = [{"instId": "ETH-C", "pos": "1"}]
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_id="ETH-P",
            max_active=2,
            fetch_positions=lambda _ex: rows,
        )
        self.assertIsNone(msg)

    def test_oo_needs_two_slots_when_max_one(self):
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_ids=["ETH-C", "ETH-P"],
            max_active=1,
            fetch_positions=lambda _ex: [],
        )
        self.assertIsNotNone(msg)
        self.assertIn("期期", msg or "")

    def test_oo_ok_when_max_two_empty(self):
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_ids=["ETH-C", "ETH-P"],
            max_active=2,
            fetch_positions=lambda _ex: [],
        )
        self.assertIsNone(msg)

    def test_oo_block_when_one_slot_left(self):
        rows = [{"instId": "OTHER", "pos": "1"}]
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_ids=["ETH-C", "ETH-P"],
            max_active=2,
            fetch_positions=lambda _ex: rows,
        )
        self.assertIsNotNone(msg)
        self.assertIn("期期", msg or "")

    def test_fail_closed_when_fetch_none(self):
        msg = option_position_limit_block_msg(
            object(),
            opening_inst_id="ETH-C",
            max_active=1,
            fetch_positions=lambda _ex: None,
        )
        self.assertIsNotNone(msg)
        self.assertIn("无法获取", msg or "")


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