package bitget

import (
	"encoding/json"
	"fmt"
	"nofx/logger"
	"nofx/trader/types"
	"strconv"
	"strings"
)

// OpenLong opens long position
func (t *BitgetTrader) OpenLong(symbol string, quantity float64, leverage int) (map[string]interface{}, error) {
	symbol = t.convertSymbol(symbol)

	// Cancel old orders first
	if err := t.CancelAllOrders(symbol); err != nil {
		logger.Infof("  ⚠ Failed to cancel old pending orders (may not have any): %v", err)
	}

	// Set leverage
	if err := t.SetLeverage(symbol, leverage); err != nil {
		logger.Infof("  ⚠️ Failed to set leverage: %v", err)
	}

	// Format quantity
	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"marginMode":  "crossed",
		"marginCoin":  "USDT",
		"side":        "buy",
		"orderType":   "market",
		"size":        qtyStr,
		"clientOid":   genBitgetClientOid(),
	}

	logger.Infof("  📊 Bitget OpenLong: symbol=%s, qty=%s, leverage=%d", symbol, qtyStr, leverage)

	data, err := t.doRequest("POST", bitgetOrderPath, body)
	if err != nil {
		return nil, fmt.Errorf("failed to open long position: %w", err)
	}

	var order struct {
		OrderId   string `json:"orderId"`
		ClientOid string `json:"clientOid"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, fmt.Errorf("failed to parse order response: %w", err)
	}

	// Clear cache
	t.clearCache()

	logger.Infof("✓ Bitget opened long position successfully: %s", symbol)

	return map[string]interface{}{
		"orderId": order.OrderId,
		"symbol":  symbol,
		"status":  "FILLED",
	}, nil
}

// OpenShort opens short position
func (t *BitgetTrader) OpenShort(symbol string, quantity float64, leverage int) (map[string]interface{}, error) {
	symbol = t.convertSymbol(symbol)

	// Cancel old orders first
	if err := t.CancelAllOrders(symbol); err != nil {
		logger.Infof("  ⚠ Failed to cancel old pending orders (may not have any): %v", err)
	}

	// Set leverage
	if err := t.SetLeverage(symbol, leverage); err != nil {
		logger.Infof("  ⚠️ Failed to set leverage: %v", err)
	}

	// Format quantity
	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"marginMode":  "crossed",
		"marginCoin":  "USDT",
		"side":        "sell",
		"orderType":   "market",
		"size":        qtyStr,
		"clientOid":   genBitgetClientOid(),
	}

	logger.Infof("  📊 Bitget OpenShort: symbol=%s, qty=%s, leverage=%d", symbol, qtyStr, leverage)

	data, err := t.doRequest("POST", bitgetOrderPath, body)
	if err != nil {
		return nil, fmt.Errorf("failed to open short position: %w", err)
	}

	var order struct {
		OrderId   string `json:"orderId"`
		ClientOid string `json:"clientOid"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, fmt.Errorf("failed to parse order response: %w", err)
	}

	// Clear cache
	t.clearCache()

	logger.Infof("✓ Bitget opened short position successfully: %s", symbol)

	return map[string]interface{}{
		"orderId": order.OrderId,
		"symbol":  symbol,
		"status":  "FILLED",
	}, nil
}

// CloseLong closes long position
func (t *BitgetTrader) CloseLong(symbol string, quantity float64) (map[string]interface{}, error) {
	symbol = t.convertSymbol(symbol)

	// If quantity is 0, get current position
	if quantity == 0 {
		positions, err := t.GetPositions()
		if err != nil {
			return nil, err
		}
		for _, pos := range positions {
			if pos["symbol"] == symbol && pos["side"] == "long" {
				quantity = pos["positionAmt"].(float64)
				break
			}
		}
		if quantity == 0 {
			return nil, fmt.Errorf("long position not found for %s", symbol)
		}
	}

	// Format quantity
	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"marginMode":  "crossed",
		"marginCoin":  "USDT",
		"side":        "sell",
		"orderType":   "market",
		"size":        qtyStr,
		"reduceOnly":  "YES",
		"clientOid":   genBitgetClientOid(),
	}

	logger.Infof("  📊 Bitget CloseLong: symbol=%s, qty=%s", symbol, qtyStr)

	data, err := t.doRequest("POST", bitgetOrderPath, body)
	if err != nil {
		return nil, fmt.Errorf("failed to close long position: %w", err)
	}

	var order struct {
		OrderId string `json:"orderId"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, err
	}

	// Clear cache
	t.clearCache()

	logger.Infof("✓ Bitget closed long position successfully: %s", symbol)

	return map[string]interface{}{
		"orderId": order.OrderId,
		"symbol":  symbol,
		"status":  "FILLED",
	}, nil
}

// CloseShort closes short position
func (t *BitgetTrader) CloseShort(symbol string, quantity float64) (map[string]interface{}, error) {
	symbol = t.convertSymbol(symbol)

	// If quantity is 0, get current position
	if quantity == 0 {
		positions, err := t.GetPositions()
		if err != nil {
			return nil, err
		}
		for _, pos := range positions {
			if pos["symbol"] == symbol && pos["side"] == "short" {
				quantity = pos["positionAmt"].(float64)
				break
			}
		}
		if quantity == 0 {
			return nil, fmt.Errorf("short position not found for %s", symbol)
		}
	}

	// Ensure quantity is positive
	if quantity < 0 {
		quantity = -quantity
	}

	// Format quantity
	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"marginMode":  "crossed",
		"marginCoin":  "USDT",
		"side":        "buy",
		"orderType":   "market",
		"size":        qtyStr,
		"reduceOnly":  "YES",
		"clientOid":   genBitgetClientOid(),
	}

	logger.Infof("  📊 Bitget CloseShort: symbol=%s, qty=%s", symbol, qtyStr)

	data, err := t.doRequest("POST", bitgetOrderPath, body)
	if err != nil {
		return nil, fmt.Errorf("failed to close short position: %w", err)
	}

	var order struct {
		OrderId string `json:"orderId"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, err
	}

	// Clear cache
	t.clearCache()

	logger.Infof("✓ Bitget closed short position successfully: %s", symbol)

	return map[string]interface{}{
		"orderId": order.OrderId,
		"symbol":  symbol,
		"status":  "FILLED",
	}, nil
}

// SetStopLoss sets stop loss order
func (t *BitgetTrader) SetStopLoss(symbol string, positionSide string, quantity, stopPrice float64) error {
	// Bitget V2 uses plan order for stop loss
	symbol = t.convertSymbol(symbol)

	side := "sell"
	holdSide := "long"
	if strings.ToUpper(positionSide) == "SHORT" {
		side = "buy"
		holdSide = "short"
	}

	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"planType":     "loss_plan",
		"symbol":       symbol,
		"productType":  "USDT-FUTURES",
		"marginMode":   "crossed",
		"marginCoin":   "USDT",
		"triggerPrice": fmt.Sprintf("%.8f", stopPrice),
		"triggerType":  "mark_price",
		"side":         side,
		"tradeSide":    "close",
		"orderType":    "market",
		"size":         qtyStr,
		"holdSide":     holdSide,
		"clientOid":    genBitgetClientOid(),
	}

	_, err := t.doRequest("POST", "/api/v2/mix/order/place-plan-order", body)
	if err != nil {
		return fmt.Errorf("failed to set stop loss: %w", err)
	}

	logger.Infof("  ✓ [Bitget] Stop loss set: %s @ %.4f", symbol, stopPrice)
	return nil
}

// SetTakeProfit sets take profit order
func (t *BitgetTrader) SetTakeProfit(symbol string, positionSide string, quantity, takeProfitPrice float64) error {
	// Bitget V2 uses plan order for take profit
	symbol = t.convertSymbol(symbol)

	side := "sell"
	holdSide := "long"
	if strings.ToUpper(positionSide) == "SHORT" {
		side = "buy"
		holdSide = "short"
	}

	qtyStr, _ := t.FormatQuantity(symbol, quantity)

	body := map[string]interface{}{
		"planType":     "profit_plan",
		"symbol":       symbol,
		"productType":  "USDT-FUTURES",
		"marginMode":   "crossed",
		"marginCoin":   "USDT",
		"triggerPrice": fmt.Sprintf("%.8f", takeProfitPrice),
		"triggerType":  "mark_price",
		"side":         side,
		"tradeSide":    "close",
		"orderType":    "market",
		"size":         qtyStr,
		"holdSide":     holdSide,
		"clientOid":    genBitgetClientOid(),
	}

	_, err := t.doRequest("POST", "/api/v2/mix/order/place-plan-order", body)
	if err != nil {
		return fmt.Errorf("failed to set take profit: %w", err)
	}

	logger.Infof("  ✓ [Bitget] Take profit set: %s @ %.4f", symbol, takeProfitPrice)
	return nil
}

// CancelStopLossOrders cancels stop loss orders
func (t *BitgetTrader) CancelStopLossOrders(symbol string) error {
	return t.cancelPlanOrders(symbol, "loss_plan")
}

// CancelTakeProfitOrders cancels take profit orders
func (t *BitgetTrader) CancelTakeProfitOrders(symbol string) error {
	return t.cancelPlanOrders(symbol, "profit_plan")
}

// cancelPlanOrders cancels plan orders
func (t *BitgetTrader) cancelPlanOrders(symbol string, planType string) error {
	symbol = t.convertSymbol(symbol)

	// Get pending plan orders
	params := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"planType":    planType,
	}

	data, err := t.doRequest("GET", "/api/v2/mix/order/orders-plan-pending", params)
	if err != nil {
		return err
	}

	var orders struct {
		EntrustedList []struct {
			OrderId string `json:"orderId"`
		} `json:"entrustedList"`
	}

	if err := json.Unmarshal(data, &orders); err != nil {
		return err
	}

	// Cancel each order
	for _, order := range orders.EntrustedList {
		body := map[string]interface{}{
			"symbol":      symbol,
			"productType": "USDT-FUTURES",
			"marginCoin":  "USDT",
			"orderId":     order.OrderId,
		}
		t.doRequest("POST", "/api/v2/mix/order/cancel-plan-order", body)
	}

	return nil
}

// CancelAllOrders cancels all pending orders
func (t *BitgetTrader) CancelAllOrders(symbol string) error {
	symbol = t.convertSymbol(symbol)

	// Get pending orders
	params := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
	}

	data, err := t.doRequest("GET", bitgetPendingPath, params)
	if err != nil {
		return err
	}

	var orders struct {
		EntrustedList []struct {
			OrderId string `json:"orderId"`
		} `json:"entrustedList"`
	}

	if err := json.Unmarshal(data, &orders); err != nil {
		return err
	}

	// Cancel each order
	for _, order := range orders.EntrustedList {
		body := map[string]interface{}{
			"symbol":      symbol,
			"productType": "USDT-FUTURES",
			"marginCoin":  "USDT",
			"orderId":     order.OrderId,
		}
		t.doRequest("POST", bitgetCancelOrderPath, body)
	}

	// Also cancel plan orders
	t.cancelPlanOrders(symbol, "loss_plan")
	t.cancelPlanOrders(symbol, "profit_plan")

	return nil
}

// CancelStopOrders cancels stop loss and take profit orders
func (t *BitgetTrader) CancelStopOrders(symbol string) error {
	t.CancelStopLossOrders(symbol)
	t.CancelTakeProfitOrders(symbol)
	return nil
}

// GetOrderStatus gets order status
func (t *BitgetTrader) GetOrderStatus(symbol string, orderID string) (map[string]interface{}, error) {
	symbol = t.convertSymbol(symbol)

	params := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"orderId":     orderID,
	}

	data, err := t.doRequest("GET", "/api/v2/mix/order/detail", params)
	if err != nil {
		return nil, fmt.Errorf("failed to get order status: %w", err)
	}

	var order struct {
		OrderId      string `json:"orderId"`
		State        string `json:"state"`        // filled, canceled, partially_filled, new
		PriceAvg     string `json:"priceAvg"`     // Average fill price
		BaseVolume   string `json:"baseVolume"`   // Filled quantity
		Fee          string `json:"fee"`          // Fee
		Side         string `json:"side"`
		OrderType    string `json:"orderType"`
		CTime        string `json:"cTime"`
		UTime        string `json:"uTime"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, err
	}

	avgPrice, _ := strconv.ParseFloat(order.PriceAvg, 64)
	fillQty, _ := strconv.ParseFloat(order.BaseVolume, 64)
	fee, _ := strconv.ParseFloat(order.Fee, 64)
	cTime, _ := strconv.ParseInt(order.CTime, 10, 64)
	uTime, _ := strconv.ParseInt(order.UTime, 10, 64)

	// Status mapping
	statusMap := map[string]string{
		"filled":           "FILLED",
		"new":              "NEW",
		"partially_filled": "PARTIALLY_FILLED",
		"canceled":         "CANCELED",
	}

	status := statusMap[order.State]
	if status == "" {
		status = order.State
	}

	return map[string]interface{}{
		"orderId":     order.OrderId,
		"symbol":      symbol,
		"status":      status,
		"avgPrice":    avgPrice,
		"executedQty": fillQty,
		"side":        order.Side,
		"type":        order.OrderType,
		"time":        cTime,
		"updateTime":  uTime,
		"commission":  -fee,
	}, nil
}

// GetOpenOrders gets all open/pending orders for a symbol
func (t *BitgetTrader) GetOpenOrders(symbol string) ([]types.OpenOrder, error) {
	symbol = t.convertSymbol(symbol)
	var result []types.OpenOrder

	// 1. Get pending limit orders
	params := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
	}

	data, err := t.doRequest("GET", bitgetPendingPath, params)
	if err != nil {
		logger.Warnf("[Bitget] Failed to get pending orders: %v", err)
	}
	if err == nil && data != nil {
		var orders struct {
			EntrustedList []struct {
				OrderId      string `json:"orderId"`
				Symbol       string `json:"symbol"`
				Side         string `json:"side"`         // buy/sell
				TradeSide    string `json:"tradeSide"`    // open/close
				PosSide      string `json:"posSide"`      // long/short
				OrderType    string `json:"orderType"`    // limit/market
				Price        string `json:"price"`
				Size         string `json:"size"`
				State        string `json:"state"`
			} `json:"entrustedList"`
		}
		if err := json.Unmarshal(data, &orders); err == nil {
			for _, order := range orders.EntrustedList {
				price, _ := strconv.ParseFloat(order.Price, 64)
				quantity, _ := strconv.ParseFloat(order.Size, 64)

				// Convert side to standard format
				side := strings.ToUpper(order.Side)
				positionSide := strings.ToUpper(order.PosSide)

				result = append(result, types.OpenOrder{
					OrderID:      order.OrderId,
					Symbol:       symbol,
					Side:         side,
					PositionSide: positionSide,
					Type:         strings.ToUpper(order.OrderType),
					Price:        price,
					StopPrice:    0,
					Quantity:     quantity,
					Status:       "NEW",
				})
			}
		}
	}

	// 2. Get pending plan orders (stop-loss/take-profit)
	// Bitget V2 API requires planType parameter: profit_loss for SL/TP orders
	planParams := map[string]interface{}{
		"productType": "USDT-FUTURES",
		"planType":    "profit_loss",
	}

	planData, err := t.doRequest("GET", "/api/v2/mix/order/orders-plan-pending", planParams)
	if err != nil {
		logger.Warnf("[Bitget] Failed to get plan orders: %v", err)
	}
	if err == nil && planData != nil {
		var planOrders struct {
			EntrustedList []struct {
				OrderId                 string `json:"orderId"`
				Symbol                  string `json:"symbol"`
				Side                    string `json:"side"`
				PosSide                 string `json:"posSide"`
				PlanType                string `json:"planType"` // pos_loss, pos_profit
				TriggerPrice            string `json:"triggerPrice"`
				StopLossTriggerPrice    string `json:"stopLossTriggerPrice"`
				StopSurplusTriggerPrice string `json:"stopSurplusTriggerPrice"`
				Size                    string `json:"size"`
				PlanStatus              string `json:"planStatus"`
			} `json:"entrustedList"`
		}
		if err := json.Unmarshal(planData, &planOrders); err == nil {
			for _, order := range planOrders.EntrustedList {
				// Filter by symbol if specified
				if symbol != "" && order.Symbol != symbol {
					continue
				}

				// Determine trigger price based on plan type
				var triggerPrice float64
				orderType := "STOP_MARKET"

				if order.PlanType == "pos_profit" {
					// Take profit order
					orderType = "TAKE_PROFIT_MARKET"
					if order.StopSurplusTriggerPrice != "" {
						triggerPrice, _ = strconv.ParseFloat(order.StopSurplusTriggerPrice, 64)
					} else {
						triggerPrice, _ = strconv.ParseFloat(order.TriggerPrice, 64)
					}
				} else {
					// Stop loss order (pos_loss)
					if order.StopLossTriggerPrice != "" {
						triggerPrice, _ = strconv.ParseFloat(order.StopLossTriggerPrice, 64)
					} else {
						triggerPrice, _ = strconv.ParseFloat(order.TriggerPrice, 64)
					}
				}

				quantity, _ := strconv.ParseFloat(order.Size, 64)
				side := strings.ToUpper(order.Side)
				positionSide := strings.ToUpper(order.PosSide)

				result = append(result, types.OpenOrder{
					OrderID:      order.OrderId,
					Symbol:       order.Symbol,
					Side:         side,
					PositionSide: positionSide,
					Type:         orderType,
					Price:        0,
					StopPrice:    triggerPrice,
					Quantity:     quantity,
					Status:       "NEW",
				})
			}
		}
	}

	logger.Infof("✓ BITGET GetOpenOrders: found %d open orders for %s", len(result), symbol)
	return result, nil
}

// PlaceLimitOrder places a limit order for grid trading
// Implements GridTrader interface
func (t *BitgetTrader) PlaceLimitOrder(req *types.LimitOrderRequest) (*types.LimitOrderResult, error) {
	symbol := t.convertSymbol(req.Symbol)

	// Set leverage if specified
	if req.Leverage > 0 {
		if err := t.SetLeverage(symbol, req.Leverage); err != nil {
			logger.Warnf("[Bitget] Failed to set leverage: %v", err)
		}
	}

	// Format quantity
	qtyStr, _ := t.FormatQuantity(symbol, req.Quantity)

	// Determine side
	side := "buy"
	if req.Side == "SELL" {
		side = "sell"
	}

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"marginMode":  "crossed",
		"marginCoin":  "USDT",
		"side":        side,
		"orderType":   "limit",
		"size":        qtyStr,
		"price":       fmt.Sprintf("%.8f", req.Price),
		"force":       "GTC", // Good Till Cancel
		"clientOid":   genBitgetClientOid(),
	}

	// Add reduce only if specified
	if req.ReduceOnly {
		body["reduceOnly"] = "YES"
	}

	logger.Infof("[Bitget] PlaceLimitOrder: %s %s @ %.4f, qty=%s", symbol, side, req.Price, qtyStr)

	data, err := t.doRequest("POST", bitgetOrderPath, body)
	if err != nil {
		return nil, fmt.Errorf("failed to place limit order: %w", err)
	}

	var order struct {
		OrderId   string `json:"orderId"`
		ClientOid string `json:"clientOid"`
	}

	if err := json.Unmarshal(data, &order); err != nil {
		return nil, fmt.Errorf("failed to parse order response: %w", err)
	}

	logger.Infof("✓ [Bitget] Limit order placed: %s %s @ %.4f, orderID=%s",
		symbol, side, req.Price, order.OrderId)

	return &types.LimitOrderResult{
		OrderID:      order.OrderId,
		ClientID:     order.ClientOid,
		Symbol:       req.Symbol,
		Side:         req.Side,
		PositionSide: req.PositionSide,
		Price:        req.Price,
		Quantity:     req.Quantity,
		Status:       "NEW",
	}, nil
}

// CancelOrder cancels a specific order by ID
// Implements GridTrader interface
func (t *BitgetTrader) CancelOrder(symbol, orderID string) error {
	symbol = t.convertSymbol(symbol)

	body := map[string]interface{}{
		"symbol":      symbol,
		"productType": "USDT-FUTURES",
		"orderId":     orderID,
	}

	_, err := t.doRequest("POST", "/api/v2/mix/order/cancel-order", body)
	if err != nil {
		return fmt.Errorf("failed to cancel order: %w", err)
	}

	logger.Infof("✓ [Bitget] Order cancelled: %s %s", symbol, orderID)
	return nil
}
