import json
import websocket
import ssl
import threading
import time
import hmac
import hashlib
import base64

# OKX 私有 WebSocket URL
OKX_WS_URL = "wss://ws.okx.com:8443/ws/v5/private"

# API 認證資訊
API_KEY = "4a4d18ed-f671-4a26-92cb-c34388407d41"
SECRET_KEY = "A209BB83BEBC32727E3E807E43310554"
PASSPHRASE = "@89687828cC"

# 生成 OKX API 認證簽名
def generate_signature(timestamp, method, request_path, body):
    message = f"{timestamp}{method}{request_path}{body}"
    mac = hmac.new(SECRET_KEY.encode(), message.encode(), hashlib.sha256)
    return base64.b64encode(mac.digest()).decode()

# WebSocket 連線成功時的回呼函式
def on_open(ws):
    print("WebSocket連線已開啟，開始認證...")
    timestamp = str(int(time.time()))
    signature = generate_signature(timestamp, "GET", "/users/self/verify", "")
    auth_message = {
        "op": "login",
        "args": [
            {
                "apiKey": API_KEY,
                "passphrase": PASSPHRASE,
                "timestamp": timestamp,
                "sign": signature
            }
        ]
    }
    ws.send(json.dumps(auth_message))
    
    # 啟動心跳線程
    threading.Thread(target=send_heartbeat, args=(ws,), daemon=True).start()

    # 這裡可以在認證成功後進行買入操作
    # threading.Thread(target=place_order, args=(ws,), daemon=True).start()

# WebSocket 接收到訊息時的回呼函式
def on_message(ws, message):
    if message == "pong":
        print("收到 pong 訊息，連線正常")
        return  # 不需要解析 pong 訊息
    
    if not message.strip():  # 避免解析空字串
        print("⚠️ 收到空訊息，忽略")
        return
    try:
        data = json.loads(message)
    except json.JSONDecodeError:
        print(f"⚠️ 無法解析訊息: {message}")
        return
    
    print("收到的訊息:", message)
    if "event" in data and data["event"] == "login":
        print("認證成功...")

# WebSocket 連線關閉時的回呼函式
def on_close(ws, close_status_code, close_msg):
    print("WebSocket連線已關閉，準備重連...")
    reconnect_ws()  # 觸發重連

# WebSocket 錯誤時的回呼函式
def on_error(ws, error):
    print(f"WebSocket發生錯誤: {error}")
    reconnect_ws()  # 觸發重連

# 重新連接 WebSocket
def reconnect_ws():
    time.sleep(5)  # 休息5秒，避免頻繁請求
    print("正在重新連接 WebSocket...")
    start_ws()  # 重新啟動 WebSocket 連線

# **心跳線程**
def send_heartbeat(ws):
    while True:
        try:
            if ws.sock and ws.sock.connected:  # 確保連線仍然存在
                ws.send("ping")  # 發送 ping 訊息
                print("發送心跳 ping")
            time.sleep(20)  # 每 20 秒發送一次心跳
        except Exception as e:
            print(f"心跳錯誤: {e}")
            break  # 如果 WebSocket 斷開，則停止心跳線程

# 送出交易請求
def place_order(ws, side):
    """
    送出買單或賣單訂單

    :param ws: WebSocket 連線物件
    :param side: 設定訂單類型，"buy" 為買單，"sell" 為賣單
    """
    print(f"發送{side}訂單...")
    
    # 構建訂單訊息
    order_message = {
        "id": "test123456789",  # 生成唯一訂單 ID（最多 16 個字元）
        "op": "order",
        "args": [
            {
                "instId": "CSPR-USDT-SWAP",  # /USDT合約
                "tdMode": "cross",  # 逐倉模式
                "side": side,  # 買入或賣出
                "ordType": "market",  # 市價單
                "sz": "1",  # 購買/賣出 1USDT 等值的 CSPR 合約
            }
        ]
    }
    
    # 發送訂單訊息
    ws.send(json.dumps(order_message))  # 發送訂單


# 創建並啟動 WebSocket 連線
def start_ws():
    ws = websocket.WebSocketApp(
        OKX_WS_URL,
        on_open=on_open,
        on_message=on_message,
        on_close=on_close,
        on_error=on_error
    )
    ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})

if __name__ == "__main__":
    # 啟動 WebSocket 線程
    ws_thread = threading.Thread(target=start_ws, daemon=True)
    ws_thread.start()

    # 主線程保持運行，避免程式退出
    while True:
        time.sleep(1)
