import {
  describe,
  it,
  expect
} from 'vitest';
import type { Message } from '../../../../shared-kernel';
import {
  buildMessageRevision,
  materializeMessageFromRevision,
  revisionBeatsMessage
} from './message-revision.builder.rules';

function createMessage(overrides: Partial<Message> = {}): Message {
  return {
    id: 'message-1',
    roomId: 'room-1',
    senderId: 'user-1',
    senderName: 'User 1',
    content: 'hello',
    timestamp: 1_000,
    reactions: [],
    isDeleted: false,
    ...overrides
  };
}

describe('message-revision.builder.rules', () => {
  it('builds create revisions at revision zero', async () => {
    const message = createMessage();
    const revision = await buildMessageRevision({
      message,
      type: 'create',
      actorId: 'user-1',
      editedAt: 1_000
    });

    expect(revision.revision).toBe(0);
    expect(revision.headHash).toMatch(/^[a-f0-9]{64}$/);
    expect(revision.type).toBe('create');
  });

  it('increments revision for author edits', async () => {
    const message = createMessage({ revision: 0, headHash: 'abc' });
    const revision = await buildMessageRevision({
      message,
      type: 'author-edit',
      actorId: 'user-1',
      content: 'edited',
      editedAt: 2_000,
      prevRevisionHash: 'abc'
    });

    expect(revision.revision).toBe(1);
    expect(revision.prevRevisionHash).toBe('abc');
    expect(revision.content).toBe('edited');
  });

  it('materializes create revisions without an editedAt label timestamp', async () => {
    const revision = await buildMessageRevision({
      message: createMessage(),
      type: 'create',
      actorId: 'user-1',
      editedAt: 1_000
    });
    const materialized = materializeMessageFromRevision(null, revision);

    expect(materialized.timestamp).toBe(1_000);
    expect(materialized.editedAt).toBeUndefined();
    expect(materialized.revision).toBe(0);
  });

  it('materializes message state from an edit revision', async () => {
    const revision = await buildMessageRevision({
      message: createMessage(),
      type: 'author-edit',
      actorId: 'user-1',
      content: 'edited',
      editedAt: 2_000
    });
    const materialized = materializeMessageFromRevision(createMessage(), revision);

    expect(materialized.revision).toBe(1);
    expect(materialized.content).toBe('edited');
    expect(materialized.editedAt).toBe(2_000);
    expect(materialized.headHash).toBe(revision.headHash);
  });

  it('detects when a revision should replace local state', async () => {
    const local = materializeMessageFromRevision(
      createMessage({ revision: 0, headHash: 'old' }),
      await buildMessageRevision({
        message: createMessage(),
        type: 'create',
        actorId: 'user-1',
        editedAt: 1_000
      })
    );
    const incoming = await buildMessageRevision({
      message: createMessage({ revision: 0, headHash: local.headHash }),
      type: 'author-edit',
      actorId: 'user-1',
      content: 'edited',
      editedAt: 2_000,
      prevRevisionHash: local.headHash ?? ''
    });

    expect(revisionBeatsMessage(incoming, local)).toBe(true);
  });
});
