import type { DataType, NormalizedAttributeOptions } from '@sequelize/core';
import { DataTypes } from '@sequelize/core';
import { expect } from 'chai';
import { getTestDialectTeaser, sequelize } from '../../support';

function assertDataType(property: NormalizedAttributeOptions, dataType: DataType) {
  expect(property.type).to.be.instanceof(dataType);
}

describe(getTestDialectTeaser('Model'), () => {
  describe('getAttributes', () => {
    it(`returns the model's attributes`, () => {
      const Model = sequelize.define('User', { username: DataTypes.STRING }, { timestamps: false });
      const attributes = Model.getAttributes();

      expect(Object.keys(attributes)).to.eql(['id', 'username']);

      // Type must be casted or it will cause circular references errors
      assertDataType(attributes.id, DataTypes.INTEGER);
      assertDataType(attributes.username, DataTypes.STRING);

      expect(attributes.id).to.include({
        Model,
        allowNull: false,
        primaryKey: true,
        autoIncrement: true,
        _autoGenerated: true,
        fieldName: 'id',
        _modelAttribute: true,
        field: 'id',
      });
      expect(attributes.username).to.include({
        Model,
        fieldName: 'username',
        _modelAttribute: true,
        field: 'username',
      });
    });

    it('contains timestamps if enabled', () => {
      const Model = sequelize.define('User', { username: DataTypes.STRING });
      const attributes = Model.getAttributes();

      expect(Object.keys(attributes)).to.include.members(['createdAt', 'updatedAt']);

      // Type must be casted or it will cause circular references errors
      assertDataType(attributes.createdAt, DataTypes.DATE);
      assertDataType(attributes.updatedAt, DataTypes.DATE);

      expect(attributes.createdAt).to.include({
        allowNull: false,
        _autoGenerated: true,
        Model,
        fieldName: 'createdAt',
        _modelAttribute: true,
        field: 'createdAt',
      });
      expect(attributes.updatedAt).to.include({
        allowNull: false,
        _autoGenerated: true,
        Model,
        fieldName: 'updatedAt',
        _modelAttribute: true,
        field: 'updatedAt',
      });
    });

    it('contains virtual attributes', () => {
      const Model = sequelize.define(
        'User',
        {
          username: DataTypes.STRING,
          virtual: {
            type: DataTypes.VIRTUAL,
            get() {
              return 1;
            },
          },
        },
        { timestamps: false },
      );
      const attributes = Model.getAttributes();

      expect(Object.keys(attributes)).to.include.members(['virtual']);
      assertDataType(attributes.virtual, DataTypes.VIRTUAL);
      expect(attributes.virtual).to.include({
        Model,
        fieldName: 'virtual',
        _modelAttribute: true,
        field: 'virtual',
      });
    });
  });
});
