import {MiniMessageClickEvent, MiniMessageComponent, MiniMessageHoverEvent} from './mini-message.types';

/**
 * What actually arrives over the wire can be looser than the strict MiniMessageComponent
 * type: some serializers emit bare strings inside `extra` instead of {text: "..."}, and
 * some use snake_case event keys (hover_event/click_event) with different subfield names
 * (e.g. click_event.command instead of clickEvent.value). This function tolerates both
 * and always returns a clean, strictly-typed tree.
 *
 * Call this once, right after JSON.parse, before the data enters your app's state:
 *
 *   messageJson: normalizeComponent(JSON.parse(m.messageJson))
 */
export function normalizeComponent(input: unknown): MiniMessageComponent {
  if (typeof input === 'string') {
    return {text: input};
  }
  if (input === null || typeof input !== 'object') {
    return {text: ''};
  }

  const raw = input as Record<string, any>;
  const node: MiniMessageComponent = {...(raw as MiniMessageComponent)};

  node.clickEvent = normalizeClickEvent(raw['clickEvent'] ?? raw['click_event']);
  node.hoverEvent = normalizeHoverEvent(raw['hoverEvent'] ?? raw['hover_event']);
  delete node['click_event' as keyof MiniMessageComponent];
  delete node['hover_event' as keyof MiniMessageComponent];

  if (Array.isArray(raw['extra'])) {
    node.extra = raw['extra'].map((child: unknown) => normalizeComponent(child));
  }

  // auditShape(node);

  return node;
}

function normalizeClickEvent(raw: Record<string, any> | undefined): MiniMessageClickEvent | undefined {
  if (!raw) return undefined;
  const value = raw['value'] ?? raw['command'] ?? raw['url'] ?? raw['page'] ?? '';
  return {action: raw['action'], value: String(value)};
}

function normalizeHoverEvent(raw: Record<string, any> | undefined): MiniMessageHoverEvent | undefined {
  if (!raw) return undefined;
  const source = raw['value'] ?? raw['contents'];
  return {
    action: raw['action'],
    value: typeof source === 'string' ? source : source ? normalizeComponent(source) : undefined,
  };
}

export function auditShape(node: unknown, path = 'root'): void {
  if (typeof node === 'string') {
    console.warn(`Bare string in tree at ${path}:`, node);
    return;
  }
  const n = node as Record<string, unknown>;
  if (n['hover_event'] || n['click_event']) {
    console.warn(`snake_case event key at ${path}`, n);
  }
  (n['extra'] as unknown[] | undefined)?.forEach((c, i) => auditShape(c, `${path}.extra[${i}]`));
}
