/**
 * Full-Text Search module — unit tests.
 */

import { describe, it, expect } from 'vitest';
import { SearchQuerySchema, IndexEntitySchema, ReindexRequestSchema } from './types.js';

describe('SearchQuerySchema', () => {
  it('validates minimal search query', () => {
    const result = SearchQuerySchema.safeParse({ q: 'hello' });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.limit).toBe(20);
      expect(result.data.offset).toBe(0);
    }
  });

  it('validates with all options', () => {
    const result = SearchQuerySchema.safeParse({
      q: 'search term',
      entityTypes: ['user', 'item'],
      tags: ['billing', 'support'],
      from: '2026-01-01T00:00:00.000Z',
      to: '2026-12-31T23:59:59.000Z',
      limit: 50,
      offset: 10,
    });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.entityTypes).toEqual(['user', 'item']);
      expect(result.data.limit).toBe(50);
    }
  });

  it('rejects empty query', () => {
    expect(SearchQuerySchema.safeParse({ q: '' }).success).toBe(false);
  });

  it('rejects query over 500 chars', () => {
    expect(SearchQuerySchema.safeParse({ q: 'x'.repeat(501) }).success).toBe(false);
  });

  it('rejects invalid entity type', () => {
    expect(SearchQuerySchema.safeParse({ q: 'test', entityTypes: ['invalid_type'] }).success).toBe(
      false
    );
  });

  it('rejects limit over 100', () => {
    expect(SearchQuerySchema.safeParse({ q: 'test', limit: 101 }).success).toBe(false);
  });

  it('rejects negative offset', () => {
    expect(SearchQuerySchema.safeParse({ q: 'test', offset: -1 }).success).toBe(false);
  });
});

describe('IndexEntitySchema', () => {
  it('validates minimal index entry', () => {
    const result = IndexEntitySchema.safeParse({
      entityId: 'user-123',
      entityType: 'user',
      title: 'John Doe',
      searchText: 'John Doe john@example.com admin',
      deepLink: '/users/user-123',
    });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.tags).toEqual([]);
      expect(result.data.isActive).toBe(true);
    }
  });

  it('validates with tags', () => {
    const result = IndexEntitySchema.safeParse({
      entityId: 'item-456',
      entityType: 'item',
      title: 'Fix login bug',
      searchText: 'Fix login bug authentication error password reset',
      deepLink: '/items/item-456',
      tags: ['bug', 'auth', 'p0'],
      isActive: true,
    });
    expect(result.success).toBe(true);
  });

  it('rejects empty entityId', () => {
    expect(
      IndexEntitySchema.safeParse({
        entityId: '',
        entityType: 'user',
        title: 'Test',
        searchText: 'Test content',
        deepLink: '/test',
      }).success
    ).toBe(false);
  });

  it('rejects invalid entityType', () => {
    expect(
      IndexEntitySchema.safeParse({
        entityId: 'x1',
        entityType: 'invalid',
        title: 'Test',
        searchText: 'Test',
        deepLink: '/test',
      }).success
    ).toBe(false);
  });

  it('rejects too many tags', () => {
    const tags = Array.from({ length: 21 }, (_, i) => `tag${i}`);
    expect(
      IndexEntitySchema.safeParse({
        entityId: 'x1',
        entityType: 'user',
        title: 'Test',
        searchText: 'Test',
        deepLink: '/test',
        tags,
      }).success
    ).toBe(false);
  });
});

describe('ReindexRequestSchema', () => {
  it('validates with entity types', () => {
    const result = ReindexRequestSchema.safeParse({
      entityTypes: ['user', 'item', 'broadcast'],
    });
    expect(result.success).toBe(true);
  });

  it('rejects empty entity types', () => {
    expect(ReindexRequestSchema.safeParse({ entityTypes: [] }).success).toBe(false);
  });

  it('rejects invalid entity type', () => {
    expect(ReindexRequestSchema.safeParse({ entityTypes: ['unknown'] }).success).toBe(false);
  });
});
