/**
 * Unit tests for src/utils/validators.ts
 */

import {
  createAgentSchema,
  updateAgentSchema,
  listAgentsQuerySchema,
  tokenRequestSchema,
  introspectRequestSchema,
  revokeRequestSchema,
  generateCredentialSchema,
  listCredentialsQuerySchema,
  auditQuerySchema,
} from '../../../src/utils/validators';

describe('validators', () => {
  // ────────────────────────────────────────────────────────────────
  // createAgentSchema
  // ────────────────────────────────────────────────────────────────
  describe('createAgentSchema', () => {
    const valid = {
      email: 'agent@sentryagent.ai',
      agentType: 'screener',
      version: '1.0.0',
      capabilities: ['resume:read'],
      owner: 'team-a',
      deploymentEnv: 'production',
    };

    it('should accept a valid request', () => {
      const { error } = createAgentSchema.validate(valid);
      expect(error).toBeUndefined();
    });

    it('should reject an invalid email', () => {
      const { error } = createAgentSchema.validate({ ...valid, email: 'not-an-email' });
      expect(error).toBeDefined();
    });

    it('should reject an invalid agentType', () => {
      const { error } = createAgentSchema.validate({ ...valid, agentType: 'invalid' });
      expect(error).toBeDefined();
    });

    it('should reject an invalid semver', () => {
      const { error } = createAgentSchema.validate({ ...valid, version: 'v1' });
      expect(error).toBeDefined();
    });

    it('should reject empty capabilities array', () => {
      const { error } = createAgentSchema.validate({ ...valid, capabilities: [] });
      expect(error).toBeDefined();
    });

    it('should reject capability with invalid format', () => {
      const { error } = createAgentSchema.validate({ ...valid, capabilities: ['invalid'] });
      expect(error).toBeDefined();
    });

    it('should reject missing required fields', () => {
      const { error } = createAgentSchema.validate({});
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // updateAgentSchema
  // ────────────────────────────────────────────────────────────────
  describe('updateAgentSchema', () => {
    it('should accept a single field update', () => {
      const { error } = updateAgentSchema.validate({ version: '2.0.0' });
      expect(error).toBeUndefined();
    });

    it('should reject an empty object (minProperties: 1)', () => {
      const { error } = updateAgentSchema.validate({});
      expect(error).toBeDefined();
    });

    it('should accept valid status values', () => {
      expect(updateAgentSchema.validate({ status: 'active' }).error).toBeUndefined();
      expect(updateAgentSchema.validate({ status: 'suspended' }).error).toBeUndefined();
      expect(updateAgentSchema.validate({ status: 'decommissioned' }).error).toBeUndefined();
    });

    it('should reject invalid status', () => {
      const { error } = updateAgentSchema.validate({ status: 'deleted' });
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // listAgentsQuerySchema
  // ────────────────────────────────────────────────────────────────
  describe('listAgentsQuerySchema', () => {
    it('should apply default values', () => {
      const { value } = listAgentsQuerySchema.validate({});
      expect(value.page).toBe(1);
      expect(value.limit).toBe(20);
    });

    it('should reject limit > 100', () => {
      const { error } = listAgentsQuerySchema.validate({ limit: 101 });
      expect(error).toBeDefined();
    });

    it('should reject page < 1', () => {
      const { error } = listAgentsQuerySchema.validate({ page: 0 });
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // tokenRequestSchema
  // ────────────────────────────────────────────────────────────────
  describe('tokenRequestSchema', () => {
    it('should accept a valid token request', () => {
      const { error } = tokenRequestSchema.validate({
        grant_type: 'client_credentials',
        client_id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
        client_secret: 'sk_live_abc123',
        scope: 'agents:read agents:write',
      });
      expect(error).toBeUndefined();
    });

    it('should reject missing grant_type', () => {
      const { error } = tokenRequestSchema.validate({ client_id: 'uuid', client_secret: 'secret' });
      expect(error).toBeDefined();
    });

    it('should reject invalid scope', () => {
      const { error } = tokenRequestSchema.validate({
        grant_type: 'client_credentials',
        scope: 'admin:all',
      });
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // introspectRequestSchema
  // ────────────────────────────────────────────────────────────────
  describe('introspectRequestSchema', () => {
    it('should accept a valid introspect request', () => {
      const { error } = introspectRequestSchema.validate({ token: 'some.jwt.token' });
      expect(error).toBeUndefined();
    });

    it('should reject missing token', () => {
      const { error } = introspectRequestSchema.validate({});
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // revokeRequestSchema
  // ────────────────────────────────────────────────────────────────
  describe('revokeRequestSchema', () => {
    it('should accept a valid revoke request', () => {
      const { error } = revokeRequestSchema.validate({ token: 'some.jwt.token' });
      expect(error).toBeUndefined();
    });

    it('should reject missing token', () => {
      const { error } = revokeRequestSchema.validate({});
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // generateCredentialSchema
  // ────────────────────────────────────────────────────────────────
  describe('generateCredentialSchema', () => {
    it('should accept empty body (expiresAt is optional)', () => {
      const { error } = generateCredentialSchema.validate({});
      expect(error).toBeUndefined();
    });

    it('should accept valid ISO 8601 expiresAt', () => {
      const { error } = generateCredentialSchema.validate({
        expiresAt: '2027-01-01T00:00:00.000Z',
      });
      expect(error).toBeUndefined();
    });

    it('should reject non-ISO date', () => {
      const { error } = generateCredentialSchema.validate({ expiresAt: '2027/01/01' });
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // listCredentialsQuerySchema
  // ────────────────────────────────────────────────────────────────
  describe('listCredentialsQuerySchema', () => {
    it('should apply defaults', () => {
      const { value } = listCredentialsQuerySchema.validate({});
      expect(value.page).toBe(1);
      expect(value.limit).toBe(20);
    });

    it('should accept status filter', () => {
      const { error } = listCredentialsQuerySchema.validate({ status: 'active' });
      expect(error).toBeUndefined();
    });

    it('should reject invalid status', () => {
      const { error } = listCredentialsQuerySchema.validate({ status: 'expired' });
      expect(error).toBeDefined();
    });
  });

  // ────────────────────────────────────────────────────────────────
  // auditQuerySchema
  // ────────────────────────────────────────────────────────────────
  describe('auditQuerySchema', () => {
    it('should apply defaults', () => {
      const { value } = auditQuerySchema.validate({});
      expect(value.page).toBe(1);
      expect(value.limit).toBe(50);
    });

    it('should accept valid audit action', () => {
      const { error } = auditQuerySchema.validate({ action: 'token.issued' });
      expect(error).toBeUndefined();
    });

    it('should reject invalid action', () => {
      const { error } = auditQuerySchema.validate({ action: 'unknown.action' });
      expect(error).toBeDefined();
    });

    it('should accept limit up to 200', () => {
      const { error } = auditQuerySchema.validate({ limit: 200 });
      expect(error).toBeUndefined();
    });

    it('should reject limit > 200', () => {
      const { error } = auditQuerySchema.validate({ limit: 201 });
      expect(error).toBeDefined();
    });
  });
});
