/**
 * User Event Types for Container → Gateway communication
 *
 * These types mirror the protobuf definitions in protobuf/user_events.proto
 * Message Type IDs:
 * - UserEvent: 0x20
 * - EventAck: 0x21
 */

// Message type IDs (must match protocol.md)
export const MSG_TYPE_USER_EVENT = 0x20;
export const MSG_TYPE_EVENT_ACK = 0x21;

// =============================================================================
// Enums
// =============================================================================

export enum EventType {
  // Trading events
  ORDER_PLACED = 0,
  ORDER_FILLED = 1,
  ORDER_CANCELLED = 2,
  ORDER_REJECTED = 3,
  ORDER_EXPIRED = 4,

  // Alert events
  ALERT_TRIGGERED = 10,
  ALERT_CREATED = 11,
  ALERT_DELETED = 12,

  // Position events
  POSITION_OPENED = 20,
  POSITION_CLOSED = 21,
  POSITION_UPDATED = 22,
  POSITION_LIQUIDATED = 23,

  // Workspace/chart events
  WORKSPACE_CHANGED = 30,
  CHART_ANNOTATION_ADDED = 31,
  CHART_ANNOTATION_REMOVED = 32,
  INDICATOR_UPDATED = 33,

  // Strategy events
  STRATEGY_STARTED = 40,
  STRATEGY_STOPPED = 41,
  STRATEGY_LOG = 42,
  STRATEGY_ERROR = 43,
  BACKTEST_COMPLETED = 44,

  // System events
  CONTAINER_STARTING = 50,
  CONTAINER_READY = 51,
  CONTAINER_SHUTTING_DOWN = 52,
  EVENT_ERROR = 53,
}

export enum Priority {
  INFORMATIONAL = 0,
  NORMAL = 1,
  CRITICAL = 2,
}

export enum ChannelType {
  ACTIVE_SESSION = 0,
  WEB = 1,
  TELEGRAM = 2,
  EMAIL = 3,
  PUSH = 4,
  DISCORD = 5,
  SLACK = 6,
}

export enum AckStatus {
  DELIVERED = 0,
  QUEUED = 1,
  ACK_ERROR = 2,
}

// =============================================================================
// Message Types
// =============================================================================

export interface ChannelPreference {
  channel: ChannelType;
  onlyIfActive: boolean;
}

export interface DeliverySpec {
  priority: Priority;
  channels: ChannelPreference[];
}

export interface UserEvent {
  userId: string;
  eventId: string;
  timestamp: number; // Unix milliseconds
  eventType: EventType;
  payload: Buffer;
  delivery: DeliverySpec;
}

export interface EventAck {
  eventId: string;
  status: AckStatus;
  errorMessage: string;
  deliveredVia?: ChannelType;
}

// =============================================================================
// Serialization
// =============================================================================

/**
 * Serialize UserEvent to wire format.
 * Format: [1 byte msg type][JSON payload]
 *
 * Note: In production, replace with proper protobuf serialization.
 */
export function serializeUserEvent(event: UserEvent): Buffer {
  const json = JSON.stringify({
    user_id: event.userId,
    event_id: event.eventId,
    timestamp: event.timestamp,
    event_type: event.eventType,
    payload: event.payload.toString('base64'),
    delivery: {
      priority: event.delivery.priority,
      channels: event.delivery.channels.map((c) => ({
        channel: c.channel,
        only_if_active: c.onlyIfActive,
      })),
    },
  });
  const msgType = Buffer.from([MSG_TYPE_USER_EVENT]);
  return Buffer.concat([msgType, Buffer.from(json)]);
}

/**
 * Deserialize UserEvent from wire format.
 */
export function deserializeUserEvent(data: Buffer): UserEvent {
  const msgType = data[0];
  if (msgType !== MSG_TYPE_USER_EVENT) {
    throw new Error(`Invalid message type: expected ${MSG_TYPE_USER_EVENT}, got ${msgType}`);
  }

  const json = JSON.parse(data.subarray(1).toString());

  return {
    userId: json.user_id,
    eventId: json.event_id,
    timestamp: json.timestamp,
    eventType: json.event_type as EventType,
    payload: Buffer.from(json.payload, 'base64'),
    delivery: {
      priority: json.delivery.priority as Priority,
      channels: json.delivery.channels.map(
        (c: { channel: number; only_if_active: boolean }) => ({
          channel: c.channel as ChannelType,
          onlyIfActive: c.only_if_active,
        })
      ),
    },
  };
}

/**
 * Serialize EventAck to wire format.
 */
export function serializeEventAck(ack: EventAck): Buffer {
  const json = JSON.stringify({
    event_id: ack.eventId,
    status: ack.status,
    error_message: ack.errorMessage,
    delivered_via: ack.deliveredVia,
  });
  const msgType = Buffer.from([MSG_TYPE_EVENT_ACK]);
  return Buffer.concat([msgType, Buffer.from(json)]);
}

/**
 * Deserialize EventAck from wire format.
 */
export function deserializeEventAck(data: Buffer): EventAck {
  const msgType = data[0];
  if (msgType !== MSG_TYPE_EVENT_ACK) {
    throw new Error(`Invalid message type: expected ${MSG_TYPE_EVENT_ACK}, got ${msgType}`);
  }

  const json = JSON.parse(data.subarray(1).toString());

  return {
    eventId: json.event_id,
    status: json.status as AckStatus,
    errorMessage: json.error_message || '',
    deliveredVia: json.delivered_via as ChannelType | undefined,
  };
}

// =============================================================================
// Payload Parsing Helpers
// =============================================================================

export interface OrderEventPayload {
  orderId: string;
  symbol: string;
  side: string;
  orderType: string;
  quantity: string;
  price?: string;
  fillPrice?: string;
  fillQuantity?: string;
  status: string;
  exchange: string;
  timestamp: number;
  strategyId?: string;
  errorMessage?: string;
}

export interface AlertEventPayload {
  alertId: string;
  symbol: string;
  condition: string;
  triggeredPrice: string;
  timestamp: number;
}

export interface PositionEventPayload {
  positionId: string;
  symbol: string;
  side: string;
  size: string;
  entryPrice: string;
  currentPrice: string;
  unrealizedPnl: string;
  realizedPnl?: string;
  leverage?: string;
  liquidationPrice?: string;
  exchange: string;
  timestamp: number;
}

export interface WorkspaceEventPayload {
  workspaceId: string;
  changeType: string;
  symbol?: string;
  timeframe?: string;
  annotationId?: string;
  annotationType?: string;
  annotationData?: string;
  indicatorName?: string;
  indicatorParams?: string;
  timestamp: number;
}

export interface StrategyEventPayload {
  strategyId: string;
  strategyName: string;
  logLevel: string;
  message: string;
  details?: string;
  timestamp: number;
}

/**
 * Parse event payload as JSON.
 * Returns the parsed object or null if parsing fails.
 */
export function parseEventPayload<T>(event: UserEvent): T | null {
  try {
    return JSON.parse(event.payload.toString()) as T;
  } catch {
    return null;
  }
}

/**
 * Get human-readable event type name.
 */
export function getEventTypeName(eventType: EventType): string {
  return EventType[eventType] || `UNKNOWN(${eventType})`;
}

/**
 * Get human-readable channel type name.
 */
export function getChannelTypeName(channelType: ChannelType): string {
  return ChannelType[channelType] || `UNKNOWN(${channelType})`;
}
