// Package dex provides the Synor DEX SDK for Go
//
// Complete decentralized exchange client with support for:
// - AMM swaps (constant product, stable, concentrated)
// - Liquidity provision
// - Perpetual futures (up to 100x leverage)
// - Order books (limit orders)
// - Farming & staking
package dex

import (
	"math/big"
	"time"
)

// PoolType represents the type of liquidity pool
type PoolType string

const (
	PoolTypeConstantProduct PoolType = "constant_product" // x * y = k
	PoolTypeStable          PoolType = "stable"           // Optimized for stablecoins
	PoolTypeConcentrated    PoolType = "concentrated"     // Uniswap v3 style
)

// PositionSide represents the side of a perpetual position
type PositionSide string

const (
	PositionSideLong  PositionSide = "long"
	PositionSideShort PositionSide = "short"
)

// OrderType represents the type of order
type OrderType string

const (
	OrderTypeMarket         OrderType = "market"
	OrderTypeLimit          OrderType = "limit"
	OrderTypeStopMarket     OrderType = "stop_market"
	OrderTypeStopLimit      OrderType = "stop_limit"
	OrderTypeTakeProfit     OrderType = "take_profit"
	OrderTypeTakeProfitLimit OrderType = "take_profit_limit"
)

// MarginType represents the margin type for perpetuals
type MarginType string

const (
	MarginTypeCross    MarginType = "cross"
	MarginTypeIsolated MarginType = "isolated"
)

// TimeInForce represents the time in force for limit orders
type TimeInForce string

const (
	TimeInForceGTC TimeInForce = "GTC" // Good Till Cancel
	TimeInForceIOC TimeInForce = "IOC" // Immediate Or Cancel
	TimeInForceFOK TimeInForce = "FOK" // Fill Or Kill
	TimeInForceGTD TimeInForce = "GTD" // Good Till Date
)

// OrderStatus represents the status of an order
type OrderStatus string

const (
	OrderStatusPending         OrderStatus = "pending"
	OrderStatusOpen            OrderStatus = "open"
	OrderStatusPartiallyFilled OrderStatus = "partially_filled"
	OrderStatusFilled          OrderStatus = "filled"
	OrderStatusCancelled       OrderStatus = "cancelled"
	OrderStatusExpired         OrderStatus = "expired"
)

// Config holds the DEX client configuration
type Config struct {
	APIKey     string
	Endpoint   string
	WSEndpoint string
	Timeout    time.Duration
	Retries    int
	Debug      bool
}

// DefaultConfig returns a Config with default values
func DefaultConfig(apiKey string) Config {
	return Config{
		APIKey:     apiKey,
		Endpoint:   "https://dex.synor.io/v1",
		WSEndpoint: "wss://dex.synor.io/v1/ws",
		Timeout:    30 * time.Second,
		Retries:    3,
		Debug:      false,
	}
}

// Token represents token information
type Token struct {
	Address     string   `json:"address"`
	Symbol      string   `json:"symbol"`
	Name        string   `json:"name"`
	Decimals    int      `json:"decimals"`
	TotalSupply *big.Int `json:"total_supply"`
	PriceUSD    *float64 `json:"price_usd,omitempty"`
	LogoURL     *string  `json:"logo_url,omitempty"`
	Verified    bool     `json:"verified"`
}

// Pool represents a liquidity pool
type Pool struct {
	ID             string   `json:"id"`
	TokenA         Token    `json:"token_a"`
	TokenB         Token    `json:"token_b"`
	PoolType       PoolType `json:"pool_type"`
	ReserveA       *big.Int `json:"reserve_a"`
	ReserveB       *big.Int `json:"reserve_b"`
	Fee            float64  `json:"fee"`
	TVLUSD         float64  `json:"tvl_usd"`
	Volume24h      float64  `json:"volume_24h"`
	APR            float64  `json:"apr"`
	LPTokenAddress string   `json:"lp_token_address"`
	TickSpacing    *int     `json:"tick_spacing,omitempty"` // For concentrated liquidity
	SqrtPrice      *string  `json:"sqrt_price,omitempty"`
}

// PoolFilter holds pool listing filters
type PoolFilter struct {
	Tokens      []string
	MinTVL      *float64
	MinVolume24h *float64
	Verified    *bool
	Limit       *int
	Offset      *int
}

// Quote represents a swap quote
type Quote struct {
	TokenIn         string   `json:"token_in"`
	TokenOut        string   `json:"token_out"`
	AmountIn        *big.Int `json:"amount_in"`
	AmountOut       *big.Int `json:"amount_out"`
	PriceImpact     float64  `json:"price_impact"`
	Route           []string `json:"route"`
	Fee             *big.Int `json:"fee"`
	MinimumReceived *big.Int `json:"minimum_received"`
	ExpiresAt       int64    `json:"expires_at"`
}

// QuoteParams holds parameters for getting a quote
type QuoteParams struct {
	TokenIn  string
	TokenOut string
	AmountIn *big.Int
	Slippage float64 // Default: 0.005
}

// SwapParams holds parameters for executing a swap
type SwapParams struct {
	TokenIn      string
	TokenOut     string
	AmountIn     *big.Int
	MinAmountOut *big.Int
	Deadline     *int64
	Recipient    *string
}

// SwapResult represents the result of a swap
type SwapResult struct {
	TransactionHash string   `json:"transaction_hash"`
	AmountIn        *big.Int `json:"amount_in"`
	AmountOut       *big.Int `json:"amount_out"`
	EffectivePrice  float64  `json:"effective_price"`
	FeePaid         *big.Int `json:"fee_paid"`
	Route           []string `json:"route"`
}

// AddLiquidityParams holds parameters for adding liquidity
type AddLiquidityParams struct {
	TokenA     string
	TokenB     string
	AmountA    *big.Int
	AmountB    *big.Int
	MinAmountA *big.Int
	MinAmountB *big.Int
	Deadline   *int64
	TickLower  *int // For concentrated liquidity
	TickUpper  *int
}

// RemoveLiquidityParams holds parameters for removing liquidity
type RemoveLiquidityParams struct {
	Pool       string
	LPAmount   *big.Int
	MinAmountA *big.Int
	MinAmountB *big.Int
	Deadline   *int64
}

// LiquidityResult represents the result of a liquidity operation
type LiquidityResult struct {
	TransactionHash string   `json:"transaction_hash"`
	AmountA         *big.Int `json:"amount_a"`
	AmountB         *big.Int `json:"amount_b"`
	LPTokens        *big.Int `json:"lp_tokens"`
	PoolShare       float64  `json:"pool_share"`
}

// LPPosition represents an LP position
type LPPosition struct {
	PoolID          string   `json:"pool_id"`
	LPTokens        *big.Int `json:"lp_tokens"`
	TokenAAmount    *big.Int `json:"token_a_amount"`
	TokenBAmount    *big.Int `json:"token_b_amount"`
	ValueUSD        float64  `json:"value_usd"`
	UnclaimedFeesA  *big.Int `json:"unclaimed_fees_a"`
	UnclaimedFeesB  *big.Int `json:"unclaimed_fees_b"`
	ImpermanentLoss float64  `json:"impermanent_loss"`
	TickLower       *int     `json:"tick_lower,omitempty"`
	TickUpper       *int     `json:"tick_upper,omitempty"`
	InRange         *bool    `json:"in_range,omitempty"`
}

// PerpMarket represents a perpetual futures market
type PerpMarket struct {
	Symbol            string  `json:"symbol"`
	BaseAsset         string  `json:"base_asset"`
	QuoteAsset        string  `json:"quote_asset"`
	IndexPrice        float64 `json:"index_price"`
	MarkPrice         float64 `json:"mark_price"`
	FundingRate       float64 `json:"funding_rate"`
	NextFundingTime   int64   `json:"next_funding_time"`
	OpenInterest      *big.Int `json:"open_interest"`
	Volume24h         float64 `json:"volume_24h"`
	PriceChange24h    float64 `json:"price_change_24h"`
	MaxLeverage       int     `json:"max_leverage"`
	MinOrderSize      *big.Int `json:"min_order_size"`
	TickSize          float64 `json:"tick_size"`
	MaintenanceMargin float64 `json:"maintenance_margin"`
	InitialMargin     float64 `json:"initial_margin"`
}

// OpenPositionParams holds parameters for opening a perpetual position
type OpenPositionParams struct {
	Market     string
	Side       PositionSide
	Size       *big.Int
	Leverage   int // 1-100x
	OrderType  OrderType
	LimitPrice *float64
	StopLoss   *float64
	TakeProfit *float64
	MarginType MarginType // Default: Cross
	ReduceOnly bool
}

// ClosePositionParams holds parameters for closing a perpetual position
type ClosePositionParams struct {
	Market     string
	Size       *big.Int // nil = close entire position
	OrderType  OrderType
	LimitPrice *float64
}

// ModifyPositionParams holds parameters for modifying a perpetual position
type ModifyPositionParams struct {
	PositionID    string
	NewLeverage   *int
	NewMargin     *big.Int
	NewStopLoss   *float64
	NewTakeProfit *float64
}

// PerpPosition represents a perpetual position
type PerpPosition struct {
	ID               string       `json:"id"`
	Market           string       `json:"market"`
	Side             PositionSide `json:"side"`
	Size             *big.Int     `json:"size"`
	EntryPrice       float64      `json:"entry_price"`
	MarkPrice        float64      `json:"mark_price"`
	LiquidationPrice float64      `json:"liquidation_price"`
	Margin           *big.Int     `json:"margin"`
	Leverage         int          `json:"leverage"`
	UnrealizedPNL    *big.Int     `json:"unrealized_pnl"`
	RealizedPNL      *big.Int     `json:"realized_pnl"`
	MarginRatio      float64      `json:"margin_ratio"`
	StopLoss         *float64     `json:"stop_loss,omitempty"`
	TakeProfit       *float64     `json:"take_profit,omitempty"`
	CreatedAt        int64        `json:"created_at"`
	UpdatedAt        int64        `json:"updated_at"`
}

// PerpOrder represents a perpetual order
type PerpOrder struct {
	ID         string       `json:"id"`
	Market     string       `json:"market"`
	Side       PositionSide `json:"side"`
	OrderType  OrderType    `json:"order_type"`
	Size       *big.Int     `json:"size"`
	Price      *float64     `json:"price,omitempty"`
	FilledSize *big.Int     `json:"filled_size"`
	Status     OrderStatus  `json:"status"`
	ReduceOnly bool         `json:"reduce_only"`
	CreatedAt  int64        `json:"created_at"`
}

// FundingPayment represents a funding payment record
type FundingPayment struct {
	Market       string   `json:"market"`
	Amount       *big.Int `json:"amount"`
	Rate         float64  `json:"rate"`
	PositionSize *big.Int `json:"position_size"`
	Timestamp    int64    `json:"timestamp"`
}

// OrderBookEntry represents an order book entry
type OrderBookEntry struct {
	Price  float64  `json:"price"`
	Size   *big.Int `json:"size"`
	Orders int      `json:"orders"`
}

// OrderBook represents an order book
type OrderBook struct {
	Market    string           `json:"market"`
	Bids      []OrderBookEntry `json:"bids"`
	Asks      []OrderBookEntry `json:"asks"`
	Timestamp int64            `json:"timestamp"`
}

// LimitOrderParams holds parameters for placing a limit order
type LimitOrderParams struct {
	Market      string
	Side        string // "buy" or "sell"
	Price       float64
	Size        *big.Int
	TimeInForce TimeInForce
	PostOnly    bool
}

// Order represents a limit order
type Order struct {
	ID          string      `json:"id"`
	Market      string      `json:"market"`
	Side        string      `json:"side"`
	Price       float64     `json:"price"`
	Size        *big.Int    `json:"size"`
	FilledSize  *big.Int    `json:"filled_size"`
	Status      OrderStatus `json:"status"`
	TimeInForce TimeInForce `json:"time_in_force"`
	PostOnly    bool        `json:"post_only"`
	CreatedAt   int64       `json:"created_at"`
	UpdatedAt   int64       `json:"updated_at"`
}

// Farm represents a yield farm
type Farm struct {
	ID           string   `json:"id"`
	Name         string   `json:"name"`
	StakeToken   Token    `json:"stake_token"`
	RewardTokens []Token  `json:"reward_tokens"`
	TVLUSD       float64  `json:"tvl_usd"`
	APR          float64  `json:"apr"`
	DailyRewards []*big.Int `json:"daily_rewards"`
	LockupPeriod *int64   `json:"lockup_period,omitempty"`
	MinStake     *big.Int `json:"min_stake,omitempty"`
}

// StakeParams holds parameters for staking
type StakeParams struct {
	Farm   string
	Amount *big.Int
}

// FarmPosition represents a farm position
type FarmPosition struct {
	FarmID         string     `json:"farm_id"`
	StakedAmount   *big.Int   `json:"staked_amount"`
	PendingRewards []*big.Int `json:"pending_rewards"`
	StakedAt       int64      `json:"staked_at"`
	UnlockAt       *int64     `json:"unlock_at,omitempty"`
}

// OHLCV represents OHLCV candle data
type OHLCV struct {
	Timestamp int64   `json:"timestamp"`
	Open      float64 `json:"open"`
	High      float64 `json:"high"`
	Low       float64 `json:"low"`
	Close     float64 `json:"close"`
	Volume    float64 `json:"volume"`
}

// TradeHistory represents a trade history entry
type TradeHistory struct {
	ID        string   `json:"id"`
	Market    string   `json:"market"`
	Side      string   `json:"side"`
	Price     float64  `json:"price"`
	Size      *big.Int `json:"size"`
	Timestamp int64    `json:"timestamp"`
	Maker     string   `json:"maker"`
	Taker     string   `json:"taker"`
}

// VolumeStats represents volume statistics
type VolumeStats struct {
	Volume24h        float64 `json:"volume_24h"`
	Volume7d         float64 `json:"volume_7d"`
	Volume30d        float64 `json:"volume_30d"`
	Trades24h        int     `json:"trades_24h"`
	UniqueTraders24h int     `json:"unique_traders_24h"`
}

// TVLStats represents TVL statistics
type TVLStats struct {
	TotalTVL float64 `json:"total_tvl"`
	PoolsTVL float64 `json:"pools_tvl"`
	FarmsTVL float64 `json:"farms_tvl"`
	PerpsTVL float64 `json:"perps_tvl"`
}

// Subscription represents a WebSocket subscription
type Subscription struct {
	ID      string
	Channel string
	Cancel  func()
}

// Callback types
type PriceCallback func(price float64)
type TradeCallback func(trade TradeHistory)
type OrderBookCallback func(book OrderBook)
type PositionCallback func(position PerpPosition)

// DexError represents a DEX SDK error
type DexError struct {
	Message string
	Code    string
	Status  int
}

func (e *DexError) Error() string {
	return e.Message
}

// NewDexError creates a new DexError
func NewDexError(message string, code string, status int) *DexError {
	return &DexError{
		Message: message,
		Code:    code,
		Status:  status,
	}
}
