"""Paper Trading Execution Engine (Zero Keys Required)."""
from __future__ import annotations

import time
import uuid
from datetime import datetime, timezone
from decimal import Decimal
from typing import Any, Optional

from backend.app.audit.logger import audit_logger
from backend.app.config.settings import settings
from backend.app.database.session import db_manager
from backend.app.market_data.feed_manager import feed_manager
from backend.app.monitoring.metrics import metrics_collector
from backend.app.schemas.order import OrderIntent, OrderResult, OrderSide, OrderStatus


class PaperExecutionEngine:
    """Simulates realistic matching against real-time market data with fees and slippage."""

    def __init__(
        self,
        taker_fee_pct: float = 0.00055,
        slippage_pct: float = 0.00020,
    ) -> None:
        self.taker_fee_pct = Decimal(str(taker_fee_pct))
        self.slippage_pct = Decimal(str(slippage_pct))

    def execute_order(self, intent: OrderIntent) -> OrderResult:
        # Check duplicate client order ID
        existing = db_manager.execute_read_one("SELECT id FROM orders WHERE id = ?", (intent.client_order_id,))
        if existing:
            return OrderResult(
                client_order_id=intent.client_order_id,
                exchange_order_id=None,
                status=OrderStatus.REJECTED,
                message="Duplicate client_order_id detected.",
            )

        now = datetime.now(timezone.utc).isoformat()

        # 1. Persist initial order state as REQUESTED -> SUBMITTED
        db_manager.execute_write(
            """
            INSERT INTO orders (id, exchange_order_id, risk_decision_id, mode, symbol, side, order_type, quantity, price, stop_loss, take_profit, status, created_at, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                intent.client_order_id,
                f"paper_{int(time.time()*1000)}",
                None,
                "PAPER",
                intent.symbol,
                intent.side.value,
                intent.order_type.value,
                str(intent.quantity),
                str(intent.price or "0"),
                str(intent.stop_loss or ""),
                str(intent.take_profit or ""),
                OrderStatus.SUBMITTED.value,
                now,
                now,
            ),
        )

        # 2. Fetch current market price
        ticker = feed_manager.fetch_ticker(intent.symbol)
        fill_price = ticker.last_price

        # Apply slippage
        if intent.side == OrderSide.BUY:
            fill_price = fill_price * (Decimal("1") + self.slippage_pct)
        else:
            fill_price = fill_price * (Decimal("1") - self.slippage_pct)

        fee_paid = fill_price * intent.quantity * self.taker_fee_pct

        # 3. Record fill
        exec_id = str(uuid.uuid4())
        db_manager.execute_write(
            """
            INSERT INTO order_executions (id, order_id, exec_qty, exec_price, exec_fee, fee_asset, exec_time)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            """,
            (
                exec_id,
                intent.client_order_id,
                str(intent.quantity),
                str(fill_price),
                str(fee_paid),
                "USDT",
                now,
            ),
        )

        # 4. Update order status to FILLED
        db_manager.execute_write(
            "UPDATE orders SET status = ?, updated_at = ? WHERE id = ?",
            (OrderStatus.FILLED.value, now, intent.client_order_id),
        )

        # 5. Update or create simulated position
        self._update_position(intent, fill_price, now)

        metrics_collector.record_order()
        audit_logger.info(
            "PAPER ORDER FILLED: %s %s Qty=%s at $%s Fee=$%s",
            intent.side.value,
            intent.symbol,
            intent.quantity,
            fill_price,
            fee_paid,
        )

        return OrderResult(
            client_order_id=intent.client_order_id,
            exchange_order_id=f"paper_{int(time.time()*1000)}",
            status=OrderStatus.FILLED,
            filled_qty=intent.quantity,
            avg_price=fill_price,
            fee_paid=fee_paid,
            message="Simulated fill completed successfully.",
        )

    def _update_position(self, intent: OrderIntent, fill_price: Decimal, timestamp: str) -> None:
        """Create or update paper position."""
        pos_side = "LONG" if intent.side == OrderSide.BUY else "SHORT"
        pos_id = str(uuid.uuid4())
        db_manager.execute_write(
            """
            INSERT INTO positions (id, symbol, mode, side, quantity, entry_price, current_price, stop_loss, take_profit, unrealized_pnl, realized_pnl, is_open, opened_at, closed_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, NULL)
            """,
            (
                pos_id,
                intent.symbol,
                "PAPER",
                pos_side,
                str(intent.quantity),
                str(fill_price),
                str(fill_price),
                str(intent.stop_loss or "0"),
                str(intent.take_profit or "0"),
                "0.0",
                "0.0",
                timestamp,
            ),
        )


paper_engine = PaperExecutionEngine()
