/**
 * Copyright IBM Corp. 2024, 2025
 */
import {
  BaseModel,
  IfConditionSchema,
  MetadataModel,
} from '../../src/schemas/shared.schema.js';

jest.mock('@apic/api-model/common/Metadata.js', () => ({
  Metadata_TypeEnum: {
    REST: 'REST',
    SWAGGER: 'SWAGGER',
    SOAP: 'SOAP',
    GRAPHQL: 'GRAPHQL',
    ODATA: 'ODATA',
  },
}));

describe('MetadataModel', () => {
  it('should validate a valid metadata object', () => {
    const input = {
      name: 'MySuite',
      version: '1.0.0',
      namespace: 'test',
      tags: ['tag1', 'tag2'],
    };

    expect(() => MetadataModel.parse(input)).not.toThrow();
  });

  it('should allow tags to be optional', () => {
    const input = {
      name: 'NoTags',
      version: '1.0.1',
      namespace: 'test',
    };

    const result = MetadataModel.parse(input);
    expect(result).toEqual({
      name: 'NoTags',
      version: '1.0.1',
      namespace: 'test',
    });
  });

  it('should throw if a required field is missing', () => {
    const input = {
      name: 'Incomplete',
      version: '1.0.2',
    };
    expect(() => MetadataModel.parse(input)).toThrow();
  });

  it('should throw if tags is not an array of strings', () => {
    const input = {
      name: 'InvalidTags',
      version: '1.0.3',
      namespace: 'test',
      tags: [1, 2],
    };

    expect(() => MetadataModel.parse(input)).toThrow();
  });
});

describe('BaseModel schema', () => {
  it('should validate a valid BaseModel object with empty spec', () => {
    const input = {
      kind: 'exampleKind',
      metadata: {
        name: 'TestName',
        version: '1.0.0',
        namespace: 'testNamespace',
      },
      spec: {},
    };

    expect(() => BaseModel.parse(input)).not.toThrow();
  });

  it('should fail if kind is missing', () => {
    const input = {
      metadata: {
        name: 'TestName',
        version: '1.0.0',
        namespace: 'testNamespace',
      },
      spec: {},
    };

    expect(() => BaseModel.parse(input)).toThrow(/kind/);
  });

  it('should fail if metadata is invalid', () => {
    const input = {
      kind: 'exampleKind',
      metadata: {
        name: 'TestName',
      },
      spec: {},
    };

    expect(() => BaseModel.parse(input)).toThrow(/version/);
  });

  it('should fail if spec is not an object', () => {
    const input = {
      kind: 'exampleKind',
      metadata: {
        name: 'TestName',
        version: '1.0.0',
        namespace: 'testNamespace',
      },
      spec: null,
    };

    expect(() => BaseModel.parse(input)).toThrow(/spec/);
  });
});

describe('IfConditionSchema', () => {
  it('validates simple expressions with variable', () => {
    expect(() => IfConditionSchema.parse('${var} > 5')).not.toThrow();
  });

  it('validates boolean expression', () => {
    expect(() => IfConditionSchema.parse(false)).not.toThrow();
  });

  it('validates complex expressions', () => {
    expect(() => IfConditionSchema.parse('${count} + 3 === 10')).not.toThrow();
  });

  it('fails if input is missing variable', () => {
    expect(() => IfConditionSchema.parse('5 + 2')).toThrow(
      'Invalid condition: not a valid JavaScript expression',
    );
  });

  it('fails on random string', () => {
    expect(() => IfConditionSchema.parse('hello world')).toThrow(
      'Invalid condition: not a valid JavaScript expression',
    );
  });
});
