"""Tests for order tools."""

from __future__ import annotations

import os
import tempfile
from unittest.mock import patch

import pytest

from liquidtrading.errors import (
    InsufficientBalanceError,
    RateLimitError,
    SymbolNotFoundError,
)
from liquid_mcp.config import Config, set_config


class TestPlaceOrder:
    def test_place_order_success(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="BTC-PERP", side="buy", size=100, ctx=None,
                )
                assert result["order_id"] == "ord_123"
                assert result["status"] == "filled"
                assert "next_steps" in result
                mock_client.place_order.assert_called_once()

    def test_place_order_dry_run(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="BTC-PERP", side="buy", size=100, dry_run=True, ctx=None,
                )
                assert result["dry_run"] is True
                assert result["status"] == "ok"
                assert "would_execute" in result
                mock_client.place_order.assert_not_called()

    def test_place_order_exceeds_max(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=50.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                with pytest.raises(ValueError, match="exceeds max"):
                    place_order(symbol="BTC-PERP", side="buy", size=100, ctx=None)

    def test_place_order_symbol_not_found(self, mock_client):
        mock_client.place_order.side_effect = SymbolNotFoundError(
            code="SYMBOL_NOT_FOUND", message="Symbol FAKE-PERP not found",
        )
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="FAKE-PERP", side="buy", size=100, ctx=None,
                )
                assert result["error"] is True
                assert result["error_code"] == "SYMBOL_NOT_FOUND"
                assert "get_markets" in result["next_steps"]

    def test_place_order_insufficient_balance(self, mock_client):
        mock_client.place_order.side_effect = InsufficientBalanceError(
            code="INSUFFICIENT_BALANCE", message="Not enough balance",
        )
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="BTC-PERP", side="buy", size=100, ctx=None,
                )
                assert result["error"] is True
                assert "get_account" in result["next_steps"]

    def test_place_order_rate_limited(self, mock_client):
        mock_client.place_order.side_effect = RateLimitError(
            code="RATE_LIMIT_EXCEEDED", message="Too many requests",
            status_code=429, retry_after=5.0,
        )
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="BTC-PERP", side="buy", size=100, ctx=None,
                )
                assert result["error"] is True
                assert result["retry_after"] == 5.0

    def test_place_order_high_leverage_warning(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_order

                result = place_order(
                    symbol="BTC-PERP", side="buy", size=100, leverage=50, ctx=None,
                )
                assert any("leverage" in w.lower() for w in result.get("warnings", []))


class TestPlaceBracketOrder:
    def test_bracket_order_success(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_bracket_order

                result = place_bracket_order(
                    symbol="BTC-PERP", side="buy", size=100,
                    tp=52000, sl=48000, ctx=None,
                )
                assert result["order_id"] == "ord_123"
                assert "next_steps" in result

    def test_bracket_order_dry_run(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_bracket_order

                result = place_bracket_order(
                    symbol="BTC-PERP", side="buy", size=100,
                    tp=52000, sl=48000, dry_run=True, ctx=None,
                )
                assert result["dry_run"] is True
                assert "would_execute" in result
                mock_client.place_order.assert_not_called()

    def test_bracket_order_symbol_not_found(self, mock_client):
        mock_client.place_order.side_effect = SymbolNotFoundError(
            code="SYMBOL_NOT_FOUND", message="Symbol FAKE-PERP not found",
        )
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import place_bracket_order

                result = place_bracket_order(
                    symbol="FAKE-PERP", side="buy", size=100,
                    tp=52000, sl=48000, ctx=None,
                )
                assert result["error"] is True
                assert "get_markets" in result["next_steps"]


class TestCancelOrder:
    def test_cancel_order(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import cancel_order

                result = cancel_order("ord_123", ctx=None)
                assert result["status"] == "cancelled"
                assert "next_steps" in result

    def test_cancel_order_dry_run(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import cancel_order

                result = cancel_order("ord_123", dry_run=True, ctx=None)
                assert result["dry_run"] is True
                assert "would_execute" in result
                mock_client.cancel_order.assert_not_called()


class TestCancelAllOrders:
    def test_cancel_all(self, mock_client):
        with tempfile.TemporaryDirectory() as tmpdir:
            set_config(Config(
                api_key="lq_test", api_secret="sk_test", base_url=None,
                max_order_usd=1000.0, daily_loss_limit=5000.0,
                audit_path=os.path.join(tmpdir, "trades.jsonl"),
            ))
            with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
                from liquid_mcp.tools.orders import cancel_all_orders

                result = cancel_all_orders(ctx=None)
                assert result["cancelled_count"] == 3
                assert "next_steps" in result


class TestGetOrders:
    def test_get_open_orders(self, mock_client):
        with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
            from liquid_mcp.tools.orders import get_open_orders

            result = get_open_orders(ctx=None)
            assert len(result["orders"]) == 1
            assert "next_steps" in result

    def test_get_order(self, mock_client):
        with patch("liquid_mcp.tools.orders.get_client", return_value=mock_client):
            from liquid_mcp.tools.orders import get_order

            result = get_order("ord_123", ctx=None)
            assert result["order_id"] == "ord_123"
            assert "next_steps" in result
