#!/usr/bin/env node
'use strict';

function clone(value) {
  return value == null ? value : JSON.parse(JSON.stringify(value));
}

function asText(value) {
  return typeof value === 'string' ? value : undefined;
}

function buildBaseEvent(dialect, raw, position, parsed) {
  return {
    v: 'events/v1',
    seq: position,
    position,
    dialect,
    kind: 'status',
    subtype: 'unknown',
    raw,
    parsed: clone(parsed),
  };
}

function normalizeWrapperEvent(parsed, event) {
  if (parsed && parsed.kind === 'usage' && parsed.usage && typeof parsed.usage === 'object') {
    event.kind = 'usage';
    event.subtype = asText(parsed.subtype) || 'final';
    event.usage = clone(parsed.usage);
    return event;
  }
  if (parsed && parsed.kind === 'error' && parsed.error && typeof parsed.error === 'object') {
    event.kind = 'error';
    event.subtype = asText(parsed.subtype) || 'error';
    event.error = clone(parsed.error);
    return event;
  }
  return null;
}

function normalizeClaude(parsed, event) {
  event.subtype = asText(parsed.type) || 'unknown';
  if (parsed.type === 'content_block_delta' && parsed.delta && parsed.delta.type === 'text_delta') {
    event.kind = 'message';
    event.subtype = 'text_delta';
    event.text = asText(parsed.delta.text) || '';
    return event;
  }
  if (parsed.type === 'message_start') {
    event.kind = 'status';
    event.role = asText(parsed.message && parsed.message.role);
    return event;
  }
  if (parsed.type === 'tool_use' || parsed.type === 'tool_call') {
    event.kind = 'tool_call';
    event.tool = {
      name: asText(parsed.name),
      arguments: parsed.input != null ? clone(parsed.input) : clone(parsed.arguments),
    };
    return event;
  }
  if (parsed.type === 'error') {
    event.kind = 'error';
    event.error = {
      code: asText(parsed.error && parsed.error.type) || 'claude_error',
      message: asText(parsed.error && parsed.error.message) || 'Claude error event',
    };
    return event;
  }
  return event;
}

function normalizeCursor(parsed, event) {
  event.subtype = asText(parsed.type) || 'unknown';
  if (parsed.type === 'message') {
    event.kind = 'message';
    event.role = asText(parsed.role);
    event.text = asText(parsed.text) || '';
    return event;
  }
  if (parsed.type === 'tool_call') {
    event.kind = 'tool_call';
    event.tool = {
      name: asText(parsed.name),
      arguments: clone(parsed.arguments),
    };
    return event;
  }
  if (parsed.type === 'error') {
    event.kind = 'error';
    event.error = {
      code: asText(parsed.code) || 'cursor_error',
      message: asText(parsed.message) || 'Cursor error event',
    };
    return event;
  }
  return event;
}

function normalizeCodex(parsed, event) {
  event.subtype = asText(parsed.event) || 'unknown';
  if (parsed.event === 'response.output_text.delta') {
    event.kind = 'message';
    event.text = asText(parsed.delta) || '';
    return event;
  }
  if (parsed.event === 'response.tool_call') {
    event.kind = 'tool_call';
    event.tool = {
      name: asText(parsed.name),
      arguments: parsed.arguments == null ? undefined : clone(parsed.arguments),
    };
    return event;
  }
  if (parsed.event === 'error') {
    event.kind = 'error';
    event.error = {
      code: asText(parsed.code) || 'codex_error',
      message: asText(parsed.message) || 'Codex error event',
    };
    return event;
  }
  return event;
}

function normalizeGrok(parsed, event) {
  event.subtype = asText(parsed.type) || 'unknown';
  if (parsed.type === 'text') {
    event.kind = 'message';
    event.subtype = 'text';
    event.text = asText(parsed.data) || '';
    return event;
  }
  if (parsed.type === 'thought') {
    event.kind = 'message';
    event.subtype = 'thought';
    event.text = asText(parsed.data) || '';
    return event;
  }
  if (parsed.type === 'end') {
    event.kind = 'status';
    event.subtype = 'end';
    return event;
  }
  if (parsed.type === 'error') {
    event.kind = 'error';
    event.error = {
      code: asText(parsed.code) || 'grok_error',
      message: asText(parsed.message) || 'Grok error event',
    };
    return event;
  }
  return event;
}

function normalizeParsed(dialect, raw, position, parsed) {
  const event = buildBaseEvent(dialect, raw, position, parsed);
  const wrapperEvent = normalizeWrapperEvent(parsed, event);
  if (wrapperEvent) return wrapperEvent;
  switch (dialect) {
    case 'claude':
      return normalizeClaude(parsed, event);
    case 'north':
      return normalizeClaude(parsed, event);
    case 'solweb':
      return normalizeClaude(parsed, event);
    case 'cursor':
      return normalizeCursor(parsed, event);
    case 'codex':
      return normalizeCodex(parsed, event);
    case 'grok':
      return normalizeGrok(parsed, event);
    default:
      return {
        ...event,
        kind: 'error',
        error: {
          code: 'unknown_dialect',
          message: `Unsupported dialect: ${dialect}`,
        },
      };
  }
}

function normalizeEventLine(dialect, line, position) {
  try {
    const parsed = JSON.parse(line);
    return normalizeParsed(dialect, line, position, parsed);
  } catch (error) {
    return {
      v: 'events/v1',
      seq: position,
      position,
      dialect,
      kind: 'error',
      subtype: 'invalid_line',
      raw: line,
      parsed: null,
      error: {
        code: 'invalid_json',
        message: error instanceof Error ? error.message : 'Invalid JSON line',
      },
    };
  }
}

function normalizeEventLines(dialect, lines, startPosition = 0) {
  return lines.map((line, index) => normalizeEventLine(dialect, line, startPosition + index));
}

module.exports = {
  normalizeEventLine,
  normalizeEventLines,
};
