import { describe, it, expect } from 'vitest';
import { validateForResource } from '../src/admin/validate';
import type { Resource } from '../src/admin/resource-types';

// Minimal resource fixture covering the field kinds the validator handles.
const resource: Resource = {
  key: 'fixtures',
  label: 'Fixture',
  pluralLabel: 'Fixtures',
  singularLabel: 'Fixture',
  groupKey: 'system',
  list: { queryFn: () => [], columns: [] },
  ops: {},
  form: {
    fields: [
      { key: 'title', label: 'Title', kind: 'text', required: true, maxLength: 5 },
      { key: 'kind', label: 'Kind', kind: 'select', options: [{ value: 'a', label: 'A' }] },
      {
        key: 'options',
        label: 'Options',
        kind: 'multi-text',
        minItems: 2,
        maxItems: 4,
      },
      { key: 'count', label: 'Count', kind: 'number', min: 0, max: 10 },
      {
        key: 'extras',
        label: 'Extras',
        kind: 'text',
        // Only visible when kind === 'a'
        visibleWhen: (ctx) => ctx.formValues.kind === 'a',
        required: true,
      },
    ],
  },
};

const baseArgs = { resource, item: null, actingUserId: 1 };

describe('validateForResource', () => {
  it('reports required fields that are empty', () => {
    const errors = validateForResource({ ...baseArgs, data: {} });
    expect(errors.title).toBe('Title is required');
  });

  it('reports maxLength violations on text fields', () => {
    const errors = validateForResource({ ...baseArgs, data: { title: 'too long' } });
    expect(errors.title).toMatch(/5 characters or fewer/);
  });

  it('skips fields hidden by visibleWhen', () => {
    // kind = 'b' hides the 'extras' required field — no error expected
    const errors = validateForResource({
      ...baseArgs,
      data: { title: 'ok', kind: 'b' },
    });
    expect(errors.extras).toBeUndefined();
  });

  it('enforces visibleWhen-revealed required fields', () => {
    const errors = validateForResource({
      ...baseArgs,
      data: { title: 'ok', kind: 'a' },
    });
    expect(errors.extras).toBe('Extras is required');
  });

  it('enforces multi-text min/max items', () => {
    const tooFew = validateForResource({
      ...baseArgs,
      data: { title: 'ok', options: ['only-one'] },
    });
    expect(tooFew.options).toMatch(/at least 2/);

    const tooMany = validateForResource({
      ...baseArgs,
      data: { title: 'ok', options: ['1', '2', '3', '4', '5'] },
    });
    expect(tooMany.options).toMatch(/at most 4/);
  });

  it('enforces number min/max', () => {
    const tooHigh = validateForResource({
      ...baseArgs,
      data: { title: 'ok', count: 99 },
    });
    expect(tooHigh.count).toMatch(/no more than 10/);
  });

  it('returns no errors when every field is valid', () => {
    const errors = validateForResource({
      ...baseArgs,
      data: {
        title: 'ok',
        kind: 'a',
        options: ['x', 'y'],
        count: 5,
        extras: 'fine',
      },
    });
    expect(errors).toEqual({});
  });

  it('treats form: null as always valid', () => {
    const readOnly: Resource = { ...resource, form: null };
    const errors = validateForResource({
      ...baseArgs,
      resource: readOnly,
      data: {},
    });
    expect(errors).toEqual({});
  });
});
