"""Unit Tests for Execution State Machine, Paper Matching & Endpoint Isolation."""
from __future__ import annotations

import unittest
import uuid
from decimal import Decimal

from backend.app.config.settings import TradingMode, settings
from backend.app.execution.paper import PaperExecutionEngine
from backend.app.execution.state_machine import OrderStateMachine
from backend.app.market_data.bybit_client import BybitV5Client
from backend.app.schemas.order import OrderIntent, OrderSide, OrderStatus, OrderType


class TestExecutionEngine(unittest.TestCase):
    def setUp(self) -> None:
        self.paper = PaperExecutionEngine()

    def test_order_state_machine_valid_and_invalid_transitions(self) -> None:
        """Verify state machine strictly controls legal lifecycle transitions."""
        # REQUESTED -> SUBMITTED is valid
        self.assertTrue(OrderStateMachine.validate_transition(OrderStatus.REQUESTED, OrderStatus.SUBMITTED))
        # SUBMITTED -> ACCEPTED is valid
        self.assertTrue(OrderStateMachine.validate_transition(OrderStatus.SUBMITTED, OrderStatus.ACCEPTED))
        # ACCEPTED -> FILLED is valid
        self.assertTrue(OrderStateMachine.validate_transition(OrderStatus.ACCEPTED, OrderStatus.FILLED))
        # FILLED is terminal; FILLED -> CANCELLED is invalid
        self.assertFalse(OrderStateMachine.validate_transition(OrderStatus.FILLED, OrderStatus.CANCELLED))
        # REJECTED is terminal; REJECTED -> ACCEPTED is invalid
        self.assertFalse(OrderStateMachine.validate_transition(OrderStatus.REJECTED, OrderStatus.ACCEPTED))

    def test_paper_execution_and_duplicate_prevention(self) -> None:
        """Verify simulated order matches against market data and rejects duplicate client order IDs."""
        coid = f"test_{uuid.uuid4().hex[:8]}"
        intent = OrderIntent(
            client_order_id=coid,
            symbol="BTCUSDT",
            side=OrderSide.BUY,
            order_type=OrderType.MARKET,
            quantity=Decimal("0.05"),
            price=None,
            stop_loss=Decimal("59000.0"),
            take_profit=Decimal("62000.0"),
        )
        res = self.paper.execute_order(intent)
        self.assertEqual(res.status, OrderStatus.FILLED)
        self.assertGreater(res.filled_qty, Decimal("0"))
        self.assertGreater(res.avg_price, Decimal("0"))
        self.assertGreater(res.fee_paid, Decimal("0"))

        # Submit duplicate order ID
        dup_res = self.paper.execute_order(intent)
        self.assertEqual(dup_res.status, OrderStatus.REJECTED)
        self.assertIn("Duplicate", dup_res.message)

    def test_demo_and_live_endpoint_isolation(self) -> None:
        """Verify Demo client points strictly to api-demo.bybit.com and Live is hard-locked."""
        demo_client = BybitV5Client(mode=TradingMode.BYBIT_DEMO)
        self.assertEqual(demo_client.base_url, "https://api-demo.bybit.com")

        # When ENABLE_LIVE_TRADING is False, initializing Live client raises PermissionError
        settings.ENABLE_LIVE_TRADING = False
        with self.assertRaises(PermissionError):
            BybitV5Client(mode=TradingMode.LIVE)


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