/**
 * Pacifica消息序列化工具
 *
 * 负责将Pacifica交易订单序列化为标准格式以便签名
 * 确保与Pacifica API兼容的消息格式
 */

import { sha256 } from '@noble/hashes/sha256';
import { Platform, CredentialManagerError, ErrorType } from '@/core/types';

/**
 * Pacifica订单接口定义
 */
export interface PacificaOrder {
  market: string;
  side: 'bid' | 'ask';
  size: string;
  price?: string;
  order_type: 'market' | 'limit' | 'stop_market' | 'stop_limit';
  time_in_force?: 'gtc' | 'ioc' | 'fok';
  post_only?: boolean;
  reduce_only?: boolean;
  client_order_id?: string;
  trigger_price?: string;
  account?: string;
}

/**
 * 序列化的消息结构
 */
export interface SerializedMessage {
  payload: string;
  hash: Uint8Array;
  timestamp: number;
  nonce: string;
}

/**
 * Pacifica消息序列化器
 */
export class PacificaMessageSerializer {
  private static readonly PROTOCOL_VERSION = '1.0';
  private static readonly MESSAGE_TYPE_ORDER = 'order';

  /**
   * 序列化Pacifica订单为签名格式
   */
  public static serializeOrder(order: PacificaOrder, timestamp?: number): SerializedMessage {
    try {
      // 验证订单数据
      this.validateOrder(order);

      // 生成时间戳和随机数
      const ts = timestamp || Date.now();
      const nonce = this.generateNonce();

      // 构建标准化的订单对象
      const normalizedOrder = this.normalizeOrder(order);

      // 创建待签名的消息负载
      const payload = this.createPayload(normalizedOrder, ts, nonce);

      // 计算消息哈希
      const hash = sha256(new TextEncoder().encode(payload));

      return {
        payload,
        hash,
        timestamp: ts,
        nonce,
      };

    } catch (error) {
      throw new CredentialManagerError(
        `Failed to serialize Pacifica order: ${(error as Error).message}`,
        ErrorType.SERIALIZATION_ERROR,
        { order, timestamp }
      );
    }
  }

  /**
   * 序列化批量订单
   */
  public static serializeBatch(orders: PacificaOrder[], timestamp?: number): SerializedMessage[] {
    const ts = timestamp || Date.now();

    return orders.map((order, index) => {
      // 为每个订单使用稍微不同的时间戳以确保唯一性
      const orderTimestamp = ts + index;
      return this.serializeOrder(order, orderTimestamp);
    });
  }

  /**
   * 验证订单数据格式
   */
  private static validateOrder(order: PacificaOrder): void {
    // 验证必需字段
    if (!order.market || typeof order.market !== 'string') {
      throw new Error('Market is required and must be a string');
    }

    if (!order.side || !['bid', 'ask'].includes(order.side)) {
      throw new Error('Side must be either "bid" or "ask"');
    }

    if (!order.size || typeof order.size !== 'string') {
      throw new Error('Size is required and must be a string');
    }

    if (!order.order_type || !['market', 'limit', 'stop_market', 'stop_limit'].includes(order.order_type)) {
      throw new Error('Order type must be one of: market, limit, stop_market, stop_limit');
    }

    // 验证价格字段（限价订单必需）
    if ((order.order_type === 'limit' || order.order_type === 'stop_limit') && !order.price) {
      throw new Error('Price is required for limit orders');
    }

    // 验证触发价格（止损订单必需）
    if ((order.order_type === 'stop_market' || order.order_type === 'stop_limit') && !order.trigger_price) {
      throw new Error('Trigger price is required for stop orders');
    }

    // 验证数值格式
    if (isNaN(parseFloat(order.size)) || parseFloat(order.size) <= 0) {
      throw new Error('Size must be a positive number');
    }

    if (order.price && (isNaN(parseFloat(order.price)) || parseFloat(order.price) <= 0)) {
      throw new Error('Price must be a positive number');
    }

    if (order.trigger_price && (isNaN(parseFloat(order.trigger_price)) || parseFloat(order.trigger_price) <= 0)) {
      throw new Error('Trigger price must be a positive number');
    }
  }

  /**
   * 标准化订单对象，确保字段顺序一致
   */
  private static normalizeOrder(order: PacificaOrder): Record<string, any> {
    const normalized: Record<string, any> = {
      market: order.market,
      side: order.side,
      size: order.size,
      order_type: order.order_type,
    };

    // 按字母顺序添加可选字段
    if (order.account) normalized.account = order.account;
    if (order.client_order_id) normalized.client_order_id = order.client_order_id;
    if (order.post_only !== undefined) normalized.post_only = order.post_only;
    if (order.price) normalized.price = order.price;
    if (order.reduce_only !== undefined) normalized.reduce_only = order.reduce_only;
    if (order.time_in_force) normalized.time_in_force = order.time_in_force;
    if (order.trigger_price) normalized.trigger_price = order.trigger_price;

    return normalized;
  }

  /**
   * 创建消息负载
   */
  private static createPayload(order: Record<string, any>, timestamp: number, nonce: string): string {
    const message = {
      version: this.PROTOCOL_VERSION,
      type: this.MESSAGE_TYPE_ORDER,
      timestamp,
      nonce,
      data: order,
    };

    // 使用确定性JSON序列化
    return this.deterministicStringify(message);
  }

  /**
   * 确定性JSON序列化（键按字母顺序排序）
   */
  private static deterministicStringify(obj: any): string {
    if (obj === null) return 'null';
    if (typeof obj !== 'object') return JSON.stringify(obj);
    if (Array.isArray(obj)) {
      return '[' + obj.map(item => this.deterministicStringify(item)).join(',') + ']';
    }

    const keys = Object.keys(obj).sort();
    const pairs = keys.map(key => `"${key}":${this.deterministicStringify(obj[key])}`);
    return '{' + pairs.join(',') + '}';
  }

  /**
   * 生成唯一随机数
   */
  private static generateNonce(): string {
    const timestamp = Date.now().toString(36);
    const random = Math.random().toString(36).substring(2);
    return `${timestamp}_${random}`;
  }

  /**
   * 反序列化消息（用于验证）
   */
  public static deserializeMessage(payload: string): {
    version: string;
    type: string;
    timestamp: number;
    nonce: string;
    data: PacificaOrder;
  } {
    try {
      const parsed = JSON.parse(payload);

      if (parsed.version !== this.PROTOCOL_VERSION) {
        throw new Error(`Unsupported protocol version: ${parsed.version}`);
      }

      if (parsed.type !== this.MESSAGE_TYPE_ORDER) {
        throw new Error(`Unsupported message type: ${parsed.type}`);
      }

      return parsed;

    } catch (error) {
      throw new CredentialManagerError(
        `Failed to deserialize message: ${(error as Error).message}`,
        ErrorType.SERIALIZATION_ERROR,
        { payload }
      );
    }
  }

  /**
   * 验证消息哈希
   */
  public static verifyMessageHash(payload: string, expectedHash: Uint8Array): boolean {
    try {
      const calculatedHash = sha256(new TextEncoder().encode(payload));

      if (calculatedHash.length !== expectedHash.length) {
        return false;
      }

      for (let i = 0; i < calculatedHash.length; i++) {
        if (calculatedHash[i] !== expectedHash[i]) {
          return false;
        }
      }

      return true;

    } catch (error) {
      return false;
    }
  }
}