import { describe, expect, test } from 'bun:test';

import { upsertMessage } from '../repo';
import type { MessageDraft } from '../types';

interface Call {
  sql: string;
  params: unknown[];
}

class FakePool {
  calls: Call[] = [];
  stored: Record<string, Record<string, unknown>> = {};

  async query<T = Record<string, unknown>>(sql: string, params: unknown[] = []) {
    this.calls.push({ sql, params });

    if (sql.startsWith('INSERT INTO macsync.messages')) {
      const [
        id,
        device_id,
        conversation_id,
        external_id,
        provider,
        from_handle,
        body,
        is_from_me,
        has_attachments,
        attachment_count,
        sent_at,
        delivered_at,
        read_at,
        attributed_body,
        body_decoded,
      ] = params;
      this.stored[id as string] = {
        id,
        device_id,
        conversation_id,
        external_id,
        provider,
        from_handle,
        body,
        attributed_body,
        body_decoded,
        is_from_me,
        has_attachments,
        attachment_count,
        sent_at,
        delivered_at,
        read_at,
        synced_at: new Date().toISOString(),
      };
      return { rows: [] as unknown as T[] };
    }

    if (sql.startsWith('SELECT * FROM macsync.messages WHERE id')) {
      const [id] = params as [string];
      const row = this.stored[id];
      return { rows: row ? [row as unknown as T] : ([] as unknown as T[]) };
    }

    return { rows: [] as unknown as T[] };
  }
}

const baseDraft: MessageDraft = {
  id: 'msg-1',
  deviceId: 'dev-1',
  conversationId: 'conv-1',
  externalId: 'guid-1',
  provider: 'imessage',
  fromHandle: '+15551234',
  body: '',
  isFromMe: false,
  sentAt: '2026-05-13T00:00:00.000Z',
};

describe('upsertMessage', () => {
  test('passes attributed_body as Buffer and body_decoded as text to INSERT', async () => {
    const pool = new FakePool();
    const base64 = Buffer.from([0x04, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]).toString('base64');

    const result = await upsertMessage(pool as unknown as never, {
      ...baseDraft,
      attributedBody: base64,
      bodyDecoded: null,
    });

    const insert = pool.calls.find((c) => c.sql.startsWith('INSERT INTO macsync.messages'));
    expect(insert).toBeDefined();
    expect(insert!.sql).toContain('attributed_body');
    expect(insert!.sql).toContain('body_decoded');
    const params = insert!.params;
    // Position 14 (index 13): attributed_body
    expect(params[13]).toBeInstanceOf(Buffer);
    expect((params[13] as Buffer).toString('base64')).toBe(base64);
    // Position 15 (index 14): body_decoded
    expect(params[14]).toBeNull();

    // Round-trip back to base64 via hydrate
    expect(result.attributedBody).toBe(base64);
    expect(result.bodyDecoded).toBeNull();
  });

  test('passes null when attributedBody is omitted', async () => {
    const pool = new FakePool();
    const result = await upsertMessage(pool as unknown as never, { ...baseDraft, body: 'hi' });
    const insert = pool.calls.find((c) => c.sql.startsWith('INSERT INTO macsync.messages'));
    expect(insert!.params[13]).toBeNull();
    expect(insert!.params[14]).toBeNull();
    expect(result.attributedBody).toBeNull();
    expect(result.bodyDecoded).toBeNull();
  });

  test('upsert round-trips attributedBody as base64 from Buffer storage', async () => {
    const pool = new FakePool();
    const base64 = Buffer.from([0x01, 0x02, 0x03]).toString('base64');

    const result = await upsertMessage(pool as unknown as never, {
      ...baseDraft,
      id: 'msg-2',
      externalId: 'guid-2',
      attributedBody: base64,
    });
    expect(result.attributedBody).toBe(base64);
  });
});
