# STDLIB IMPORTS
from typing_extensions import Literal
from dataclasses import dataclass
from datetime import datetime, timedelta
from decimal import Decimal

from bitget.core import (
  AuthEndpoint, timestamp as ts, rate_limit,
  validator, TypedDict, Timestamp
)

# RESPONSE MODELS

class FeeDetail(TypedDict):
  deduction: str
  """Whether or not to deduct (vouchers)"""
  feeCoin: str
  """Crypto ticker"""
  totalDeductionFee: Decimal
  """Total transaction fee discount"""
  totalFee: Decimal
  """Total transaction fee"""

class Fill(TypedDict):
  tradeId: str
  """Transaction id"""
  symbol: str
  """Trading pair"""
  orderId: str
  """Order no."""
  price: Decimal
  """Order price"""
  baseVolume: Decimal
  """Amount of coins traded"""
  feeDetail: list[FeeDetail]
  """Transaction fee"""
  side: Literal['buy', 'sell']
  """Type of transaction - buy: Buy - sell: Sell"""
  quoteVolume: Decimal
  """Trading amount in quote currency"""
  profit: Decimal
  """Profit"""
  enterPointSource: str
  """Order source - WEB: Orders created on the website - API: Orders created on API - SYS: System managed orders, usually generated by forced liquidation logic - ANDROID: Orders created on the Android app - IOS: Orders created on the iOS app"""
  tradeSide: Literal[
    'close', 'open',
    'reduce_close_long', 'reduce_close_short',
    'burst_close_long', 'burst_close_short',
    'offset_close_long', 'offset_close_short',
    'delivery_close_long', 'delivery_close_short',
    'dte_sys_adl_close_long', 'dte_sys_adl_close_short',
    'buy_single', 'sell_single',
    'reduce_buy_single', 'reduce_sell_single',
    'burst_buy_single', 'burst_sell_single',
    'delivery_sell_single', 'delivery_buy_single',
    'dte_sys_adl_buy_in_single_side_mode', 'dte_sys_adl_sell_in_single_side_mode'
  ]
  """Direction - `close`: Close (open and close mode) - `open`: Open (open and close mode) - `reduce_close_long`: Liquidate partial long positions for hedge position mode - `reduce_close_short`: Liquidate partial short positions for hedge position mode - `burst_close_long`: Liquidate long positions for hedge position mode - `burst_close_short`: Liquidate short positions for hedge position mode - `offset_close_long`: Liquidate partial long positions for netting for hedge position mode - `offset_close_short`: Liquidate partial short positions for netting for hedge position mode - `delivery_close_long`: Delivery long positions for hedge position mode - `delivery_close_short`: Delivery short positions for hedge position mode - `dte_sys_adl_close_long`: ADL close long position for hedge position mode - `dte_sys_adl_close_short`: ADL close short position for hedge position mode - `buy_single`: Buy, one way postion mode - `sell_single`: Sell, one way postion mode - `reduce_buy_single`: Liquidate partial positions, buy, one way position mode - `reduce_sell_single`: Liquidate partial positions, sell, one way position mode - `burst_buy_single`: Liquidate short positions, buy, one way postion mode - `burst_sell_single`: Liquidate partial positions, sell, one way position mode - `delivery_sell_single`: Delivery sell, one way position mode - `delivery_buy_single`: Delivery buy, one way position mode - `dte_sys_adl_buy_in_single_side_mode`: ADL close position, buy, one way position mode - `dte_sys_adl_sell_in_single_side_mode`: ADL close position, sell, one way position mode"""
  posMode: Literal['one_way_mode', 'hedge_mode']
  """Position mode - `one_way_mode`: one-way position - `hedge_mode`: two-way position"""
  tradeScope: Literal['taker', 'maker']
  """Trader tag - taker: Taker - maker: Maker"""
  cTime: Timestamp
  """Date of transaction"""

class FillsResponse(TypedDict):
  fillList: list[Fill]
  """Transaction details"""
  endId: str
  """The final Transaction ID. - This is used when idLessThan/idGreaterThan is set as a range."""

validate_response = validator(FillsResponse)

# ENDPOINT CLASS

@dataclass
class Fills(AuthEndpoint):
  @rate_limit(timedelta(seconds=0.1))
  async def fills(
    self,
    product_type: Literal['USDT-FUTURES', 'COIN-FUTURES', 'USDC-FUTURES'],
    *,
    order_id: str | None = None,
    symbol: str | None = None,
    id_less_than: str | None = None,
    start: datetime | None = None,
    end: datetime | None = None,
    limit: int | None = None,
    validate: bool | None = None
  ):
    """Get Order Fill Details
    
    - `product_type`: Product type - `USDT-FUTURES` USDT-M Futures - `COIN-FUTURES` Coin-M Futures - `USDC-FUTURES` USDC-M Futures
    - `order_id`: Order ID
    - `symbol`: Trading pair, e.g. ETHUSDT
    - `id_less_than`: Requests the content on the page before the `tradeId` (older data).
    - `start`: Start time (time stamp in milliseconds) - (The maximum time span supported is three months. The default end time is three months if no value is set for the end time. ) - (For Managed Sub-Account, the StartTime cannot be earlier than the binding time)
    - `end`: End time (time stamp in milliseconds) - (The maximum time span supported is three months. The default start time is three months ago if no value is set for the start time. )
    - `limit`: Number of queries: Default: 100, maximum: 100
    - `validate`: Whether to validate the response against the expected schema (default: True).

    > [Bitget API docs](https://www.bitget.com/api-doc/contract/trade/Get-Order-Fills)
    """
    params = {}
    
    # Add required params
    params['productType'] = product_type
    
    # Add optional params conditionally
    if order_id is not None:
      params['orderId'] = order_id
    if symbol is not None:
      params['symbol'] = symbol
    if id_less_than is not None:
      params['idLessThan'] = id_less_than
    if start is not None:
      params['startTime'] = ts.dump(start)
    if end is not None:
      params['endTime'] = ts.dump(end)
    if limit is not None:
      params['limit'] = str(limit)
    
    # Make request
    r = await self.authed_request('GET', '/api/v2/mix/order/fills', params=params)
    return self.output(r.text, validate_response, validate=validate)

