"""对冲计划微信文案与到期结算."""
import sqlite3
import time
import unittest
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock

from lib.exchange.okx_options_lib import expiry_ms_from_inst_id
from lib.hedge_plan.hedge_plan_db import get_plan, init_hedge_plan_tables, insert_leg, insert_plan
from lib.hedge_plan.hedge_plan_monitor_lib import _tick_oo_expiry, _settle_orphaned_after_tp
from lib.hedge_plan.hedge_plan_notify_lib import (
    build_hedge_end_message,
    build_hedge_start_message,
    notify_plan_end,
    notify_plan_start,
)
from lib.hedge_plan.hedge_plan_settle_lib import leg_is_expired, settle_option_leg_at_spot


def _mem_db():
    conn = sqlite3.connect(":memory:")
    conn.row_factory = sqlite3.Row
    init_hedge_plan_tables(conn)
    return conn


class TestHedgeNotify(unittest.TestCase):
    def test_start_end_copy(self):
        plan = {
            "id": 7,
            "plan_type": "perp_options",
            "underlying": "ETH",
            "direction": "long",
            "entry_mark": 1800,
            "tp": 1900,
            "sl": 1700,
            "perp_size": 2,
            "leverage": 10,
            "premium_total": 1.5,
            "close_reason": "perp_tp",
            "realized_pnl_total": 12.3,
            "realized_pnl_perp": 15,
            "realized_pnl_options": -1.5,
            "opened_at": "2026-07-01 10:00:00",
            "closed_at": "2026-07-01 12:00:00",
        }
        s = build_hedge_start_message(plan)
        self.assertIn("启动 #7", s)
        self.assertIn("永期", s)
        e = build_hedge_end_message(plan)
        self.assertIn("结束 #7", e)
        self.assertIn("止盈", e)

    def test_idempotent_flags(self):
        conn = _mem_db()
        sent = []
        cfg = {"send_wechat": lambda c: sent.append(c)}
        pid = insert_plan(
            conn,
            {
                "plan_type": "options_options",
                "status": "active",
                "underlying": "ETH",
                "target_price": 2000,
                "premium_total": 2.0,
                "opened_at": "t0",
            },
        )
        plan = get_plan(conn, pid)
        self.assertTrue(notify_plan_start(cfg, conn, plan, []))
        plan = get_plan(conn, pid)
        self.assertEqual(int(plan["wechat_start_sent"]), 1)
        self.assertFalse(notify_plan_start(cfg, conn, plan, []))
        self.assertEqual(len(sent), 1)

        plan["status"] = "closed"
        plan["close_reason"] = "oo_expiry_loss"
        plan["realized_pnl_total"] = -2
        plan["closed_at"] = "t1"
        self.assertTrue(notify_plan_end(cfg, conn, plan))
        plan = get_plan(conn, pid)
        self.assertEqual(int(plan["wechat_end_sent"]), 1)
        self.assertFalse(notify_plan_end(cfg, conn, plan))
        self.assertEqual(len(sent), 2)


class TestHedgeSettle(unittest.TestCase):
    def test_put_expiry_otm(self):
        pnl = settle_option_leg_at_spot(
            {"opt_type": "P", "strike": 1700, "size": 2, "premium": 1.2, "ct_mult": 0.01},
            spot=1800,
        )
        self.assertAlmostEqual(pnl, -1.2)

    def test_call_expiry_itm(self):
        # intrinsic (1900-1800)*2*0.01 - 0.5 = 2 - 0.5
        pnl = settle_option_leg_at_spot(
            {"opt_type": "C", "strike": 1800, "size": 2, "premium": 0.5, "ct_mult": 0.01},
            spot=1900,
        )
        self.assertAlmostEqual(pnl, 1.5)

    def test_leg_expired_from_inst(self):
        # past date in inst_id
        past = datetime.now(timezone.utc) - timedelta(days=3)
        yy = past.year % 100
        tag = f"ETH-USD-{yy:02d}{past.month:02d}{past.day:02d}-1800-P"
        self.assertTrue(leg_is_expired({"inst_id": tag}))
        future = datetime.now(timezone.utc) + timedelta(days=10)
        tag2 = f"ETH-USD-{future.year % 100:02d}{future.month:02d}{future.day:02d}-1800-P"
        self.assertFalse(leg_is_expired({"inst_id": tag2}))
        self.assertIsNotNone(expiry_ms_from_inst_id(tag))


class TestHedgeMonitorExpiry(unittest.TestCase):
    def test_oo_expiry_loss_closes_plan(self):
        conn = _mem_db()
        past = datetime.now(timezone.utc) - timedelta(days=1)
        tag = f"ETH-USD-{past.year % 100:02d}{past.month:02d}{past.day:02d}-1800-P"
        pid = insert_plan(
            conn,
            {
                "plan_type": "options_options",
                "status": "active",
                "underlying": "ETH",
                "target_price": 2000,
                "premium_total": 2.0,
            },
        )
        insert_leg(
            conn,
            {
                "plan_id": pid,
                "leg_role": "option_a",
                "inst_id": tag,
                "opt_type": "P",
                "strike": 1800,
                "size": 1,
                "premium": 1.0,
                "status": "open",
            },
        )
        insert_leg(
            conn,
            {
                "plan_id": pid,
                "leg_role": "option_b",
                "inst_id": tag.replace("-P", "-C").replace("1800", "1900"),
                "opt_type": "C",
                "strike": 1900,
                "size": 1,
                "premium": 1.0,
                "status": "open",
            },
        )
        sent = []
        cfg = {
            "send_wechat": lambda c: sent.append(c),
            "fetch_index_price": lambda ex, u: 1850.0,
            "exchange_options": object(),
        }
        plan = get_plan(conn, pid)
        legs = [
            dict(r)
            for r in conn.execute("SELECT * FROM hedge_plan_legs WHERE plan_id=?", (pid,)).fetchall()
        ]
        r = _tick_oo_expiry(cfg, conn, plan, legs)
        self.assertIsNotNone(r)
        self.assertEqual(r["close_reason"], "oo_expiry_loss")
        plan2 = get_plan(conn, pid)
        self.assertEqual(plan2["status"], "closed")
        self.assertLessEqual(float(plan2["realized_pnl_total"]), 0)
        self.assertTrue(any("结束" in x for x in sent))

    def test_orphaned_option_does_not_rewrite_plan_total(self):
        conn = _mem_db()
        past = datetime.now(timezone.utc) - timedelta(days=1)
        tag = f"ETH-USD-{past.year % 100:02d}{past.month:02d}{past.day:02d}-1700-P"
        pid = insert_plan(
            conn,
            {
                "plan_type": "perp_options",
                "status": "closed",
                "underlying": "ETH",
                "direction": "long",
                "close_reason": "perp_tp",
                "realized_pnl_total": 10.0,
                "realized_pnl_options": -1.0,
                "stats_bucket": "tp",
            },
        )
        insert_leg(
            conn,
            {
                "plan_id": pid,
                "leg_role": "option_hedge",
                "inst_id": tag,
                "opt_type": "P",
                "strike": 1700,
                "size": 1,
                "premium": 1.0,
                "status": "hold_to_expiry",
                "close_reason": "orphaned_after_tp",
            },
        )
        cfg = {
            "fetch_index_price": lambda ex, u: 1800.0,
            "exchange_options": object(),
        }
        acted = _settle_orphaned_after_tp(cfg, conn)
        self.assertEqual(len(acted), 1)
        plan = get_plan(conn, pid)
        self.assertAlmostEqual(float(plan["realized_pnl_total"]), 10.0)
        leg = conn.execute("SELECT * FROM hedge_plan_legs WHERE plan_id=?", (pid,)).fetchone()
        self.assertEqual(leg["status"], "closed")
        self.assertEqual(leg["close_reason"], "expiry")


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