const { DataTypes } = require("sequelize");

module.exports = (sequelize) => {
  const Employee = sequelize.define(
    "employee",
    {
      id: {
        type: DataTypes.INTEGER,
        autoIncrement: true,
        primaryKey: true,
      },
      creation: { type: DataTypes.DATE, allowNull: false },
      modified: { type: DataTypes.DATE, allowNull: false },
      modified_by: { type: DataTypes.INTEGER, allowNull: false },
      owner: { type: DataTypes.INTEGER, allowNull: false },
      enabled: { type: DataTypes.BOOLEAN, allowNull: false },

      image: { type: DataTypes.STRING, allowNull: true },
      user_id: { type: DataTypes.INTEGER, allowNull: true },

      // identification
      employee_name: { type: DataTypes.STRING(100), allowNull: false },
      employee_number: { type: DataTypes.STRING(10), allowNull: true },
      id_number: { type: DataTypes.BIGINT, allowNull: true },
      tax_number: { type: DataTypes.BIGINT, allowNull: true },
      npwp_number: { type: DataTypes.BIGINT, allowNull: true },
      family_card_number: { type: DataTypes.BIGINT, allowNull: true },
      personal_email: { type: DataTypes.STRING(150), allowNull: true },
      company_email: { type: DataTypes.STRING(150), allowNull: true },
      mobile_no: { type: DataTypes.STRING(100), allowNull: true },
      place_of_birth: { type: DataTypes.STRING(20), allowNull: true },
      date_of_birth: { type: DataTypes.DATEONLY, allowNull: true },
      current_address: { type: DataTypes.TEXT, allowNull: true },
      id_address: { type: DataTypes.TEXT, allowNull: true },
      emergency_phone_number: { type: DataTypes.STRING(100), allowNull: true },
      family_background: { type: DataTypes.TEXT, allowNull: true },
      health_details: { type: DataTypes.TEXT, allowNull: true },

      // join
      date_of_joining: { type: DataTypes.DATEONLY, allowNull: true },
      scheduled_confirmation_date: {
        type: DataTypes.DATEONLY,
        allowNull: true,
      },
      final_confirmation_date: { type: DataTypes.DATEONLY, allowNull: true },
      contract_end_date: { type: DataTypes.DATEONLY, allowNull: true },
      notice_number_of_days: { type: DataTypes.INTEGER, allowNull: true },
      date_of_retirement: { type: DataTypes.DATEONLY, allowNull: true },

      // left
      resignation_letter_date: { type: DataTypes.DATEONLY, allowNull: true },
      relieving_date: { type: DataTypes.DATEONLY, allowNull: true },
      exit_clearance_date: { type: DataTypes.DATEONLY, allowNull: true },
      held_on: { type: DataTypes.DATEONLY, allowNull: true },

      health_insurance_number: { type: DataTypes.STRING(100), allowNull: true },
      employment_insurance_number: {
        type: DataTypes.STRING(100),
        allowNull: true,
      },

      // import
      idx: { type: DataTypes.STRING, allowNull: true },
      ids: { type: DataTypes.INTEGER, allowNull: true },
      import_from: { type: DataTypes.STRING(100), allowNull: true },

      // attendance leaves
      holiday_list: { type: DataTypes.INTEGER, allowNull: true },
      default_shift: { type: DataTypes.INTEGER, allowNull: true },
      leave_approver: { type: DataTypes.INTEGER, allowNull: true },
      expense_approver: { type: DataTypes.INTEGER, allowNull: true },
      shift_request_approver: { type: DataTypes.INTEGER, allowNull: true },

      // old
      religion: { type: DataTypes.STRING(15), allowNull: true },
      gender: { type: DataTypes.STRING(10), allowNull: true },
      shift_type: { type: DataTypes.STRING(100), allowNull: true },
      status: { type: DataTypes.STRING(10), allowNull: true },

      use_workflow: { type: DataTypes.STRING(100), allowNull: true },

      // fk
      employementtype_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      leaveapprover_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      reports_to: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      employeegrade_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      jobrole_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      employmentinsuranceprovider_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      healthinsuranceprovider_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      bloodgroup_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      bankaccount_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      bank_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      maritalstatus_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      ptkpstatus_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      religion_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      gender_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      employeestatus_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      shifttype_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      company_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      department_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
      designation_id: {
        type: DataTypes.INTEGER,
        allowNull: true,
      },
    },
    {
      tableName: "employees",
      freezeTableName: true,
      indexes: [
        // OPTIMIZATION: Index on user_id for fast user lookup
        {
          name: "idx_employees_user_id",
          fields: ["user_id"],
        },
        // OPTIMIZATION: Index on company_id for fast company-based queries
        {
          name: "idx_employees_company_id",
          fields: ["company_id"],
        },
        // OPTIMIZATION: Composite index for company_id + designation_id
        {
          name: "idx_employees_company_designation",
          fields: ["company_id", "designation_id"],
        },
      ],
    }
  );

  /**
   * Associates the Employee model with other models.
   * @param {object} models - The models to associate with.
   */
  Employee.associate = (models) => {
    /**
     * Associates the Employee model with the User model.
     * Defines a many-to-one relationship between Employee and User.
     * @param {object} models - The models to associate with.
     * @property {object} user - The User model associated with Employee.
     */
    Employee.belongsTo(models.User, { foreignKey: "user_id", as: "user" });

    /**
     * Associates the Employee model with the Company model.
     * Defines a many-to-one relationship between Employee and Company.
     * @param {object} models - The models to associate with.
     * @property {object} company - The Company model associated with Employee.
     */
    Employee.belongsTo(models.Company, {
      foreignKey: "company_id",
      as: "company",
    });

    /**
     * Associates the Employee model with the Department model.
     * Defines a many-to-one relationship between Employee and Department.
     * @param {object} models - The models to associate with.
     * @property {object} department - The Department model associated with Employee.
     */
    Employee.belongsTo(models.Department, {
      foreignKey: "department_id",
      as: "department",
    });

    /**
     * Associates the Employee model with the Designation model.
     * Defines a many-to-one relationship between Employee and Designation.
     * @param {object} models - The models to associate with.
     * @property {object} designation - The Designation model associated with Employee.
     */
    Employee.belongsTo(models.Designation, {
      foreignKey: "designation_id",
      as: "designation",
    });

    /**
     * Associates the Employee model with the Gender model.
     * Defines a one-to-one relationship between Employee and Gender.
     * @param {object} models - The models to associate with.
     * @property {object} gender - The Gender model associated with Employee.
     */
    Employee.belongsTo(models.Gender, {
      foreignKey: "gender_id",
      as: "employee_gender",
    });

    /**
     * Associates the Employee model with the EmployeeStatus model.
     * Defines a one-to-one relationship between Employee and EmployeeStatus.
     * @param {object} models - The models to associate with.
     * @property {object} employee_status - The EmployeeStatus model associated with Employee.
     */
    Employee.belongsTo(models.EmployeeStatus, {
      foreignKey: "employeestatus_id",
      as: "employeestatus",
    });

    Employee.belongsTo(models.Religion, {
      foreignKey: "religion_id",
      as: "employee_religion",
    });

    /**
     * Associates the Employee model with the Territory model.
     * Defines a many-to-many relationship between Employee and Territory.
     * @param {object} models - The models to associate with.
     * @property {object} territories - The Territory model associated with Employee.
     */
    Employee.belongsToMany(models.Territory, {
      through: models.EmployeeTerritory,
      foreignKey: "employee_id",
      otherKey: "territory_id",
      as: "territories",
    });

    /**
     * Associates the Employee model with the MomParticipant model.
     * Defines a one-to-many relationship between Employee and MomParticipant.
     * @param {object} models - The models to associate with.
     * @property {object} mom_participants - The MomParticipant model associated with Employee.
     */
    Employee.hasMany(models.MomParticipant, {
      foreignKey: "employee_id",
      as: "momparticipants",
    });

    /**
     * Associates the Employee model with the EmployeeCheckin model.
     * Defines a one-to-many relationship between Employee and EmployeeCheckin.
     * @param {object} models - The models to associate with.
     * @property {object} employee_checkins - The EmployeeCheckin model associated with Employee.
     */
    Employee.hasMany(models.EmployeeCheckin, {
      foreignKey: "employee_id",
      as: "employeecheckins",
    });

    /**
     * Associates the Employee model with the LeaveApplication model.
     * Defines a one-to-many relationship between Employee and LeaveApplication.
     * @param {object} models - The models to associate with.
     * @property {object} leave_applications - The LeaveApplication model associated with Employee.
     */
    Employee.hasMany(models.LeaveApplication, {
      foreignKey: "employee_id",
      as: "leaveapplications",
    });

    /**
     * Associates the Employee model with the AttendanceRequest model.
     * Defines a one-to-many relationship between Employee and AttendanceRequest.
     * @param {object} models - The models to associate with.
     * @property {object} attendance_requests - The AttendanceRequest model associated with Employee.
     */
    Employee.hasMany(models.AttendanceRequest, {
      foreignKey: "employee_id",
      as: "attendancerequests",
    });

    /**
     * Associates the Employee model with the ShiftType model.
     * Defines a one-to-one relationship between Employee and ShiftType.
     * @param {object} models - The models to associate with.
     * @property {object} shifttype - The ShiftType model associated with Employee.
     */
    Employee.belongsTo(models.ShiftType, {
      foreignKey: "shifttype_id",
      as: "shifttype",
    });

    /**
     * Associates the Employee model with the EmployeeRequest model.
     * Defines a one-to-one relationship between Employee and EmployeeRequest.
     * @param {object} models - The models to associate with.
     * @property {object} employeerequest - The EmployeeRequest model associated with Employee.
     */
    Employee.hasOne(models.EmployeeRequest, {
      foreignKey: "replace_employee_id",
      as: "employeerequest_replace",
    });
    /**
     * Associates the Employee model with the EmployeeRequest model.
     * Defines a one-to-one relationship between Employee and EmployeeRequest.
     * @param {object} models - The models to associate with.
     * @property {object} employeerequest_internal - The EmployeeRequest model associated with Employee, where the Employee is the internal employee of the request.
     */
    Employee.hasOne(models.EmployeeRequest, {
      foreignKey: "internal_employee_id",
      as: "employeerequest_internal",
    });

    /**
     * Associates the Employee model with the AbsenceClarification model.
     * Defines a one-to-many relationship between Employee and AbsenceClarification.
     * @param {object} models - The models to associate with.
     * @property {object} absenceclarifications - The AbsenceClarification model associated with Employee.
     */
    Employee.hasMany(models.AbsenceClarification, {
      foreignKey: "employee_id",
      as: "absenceclarifications",
    });

    /**
     * Associates the Employee model with the EmployeeRequest model.
     * Defines a one-to-many relationship between Employee and EmployeeRequest.
     * A Employee can be the replace employee of many EmployeeRequests.
     * @param {object} models - The models to associate with.
     * @property {object} replace_employee - The EmployeeRequest model associated with Employee, where the Employee is the replace employee of the request.
     */
    Employee.hasMany(models.EmployeeRequest, {
      foreignKey: "replace_employee_id",
      as: "replace_employee",
    });

    /**
     * Associates the Employee model with the EmployeeRequest model.
     * Defines a one-to-many relationship between Employee and EmployeeRequest.
     * A Employee can be the internal employee of many EmployeeRequests.
     * @param {object} models - The models to associate with.
     * @property {object} internal_employee - The EmployeeRequest model associated with Employee, where the Employee is the internal employee of the request.
     */
    Employee.hasMany(models.EmployeeRequest, {
      foreignKey: "internal_employee_id",
      as: "internal_employee",
    });

    /**
     * Associates the Employee model with the DeliveryTrip model.
     * Defines a one-to-many relationship between Employee and DeliveryTrip.
     * A Employee can be the driver of many DeliveryTrips.
     * @param {object} models - The models to associate with.
     * @property {object} driver_info - The DeliveryTrip model associated with Employee, where the Employee is the driver of the trip.
     */
    Employee.hasMany(models.DeliveryTrip, {
      foreignKey: "driver",
      as: "driver_info",
    });

    /**
     * Associates the Employee model with the BankAccount model.
     * Defines a one-to-many relationship between Employee and BankAccount.
     * A Employee can have many BankAccounts.
     * @param {object} models - The models to associate with.
     * @property {object} bankaccounts - The BankAccount model associated with Employee.
     */
    Employee.hasMany(models.BankAccount, {
      foreignKey: "employee_id",
      as: "bankaccounts",
    });

    Employee.hasMany(models.NcProductFU, {
      foreignKey: "pic_id",
      as: "ncproductfus",
    });

    /**
     * Associates the Employee model with the EmployeeGroupTable model.
     * Defines a one-to-many relationship between Employee and EmployeeGroupTable.
     * A Employee can be a member of many EmployeeGroups.
     * @param {object} models - The models to associate with.
     * @property {object} employeegrouptable - The EmployeeGroupTable model associated with Employee.
     */
    Employee.hasMany(models.EmployeeGroupTable, {
      foreignKey: "employee_id",
      as: "employeegrouptables",
    });

    /**
     * Associates the Employee model with the TrackingLocation model.
     * Defines a one-to-many relationship between Employee and TrackingLocation.
     * A Employee can have many TrackingLocations.
     * @param {object} models - The models to associate with.
     * @property {object} trackinglocations - The TrackingLocation model associated with Employee.
     */
    Employee.hasMany(models.TrackingLocation, {
      foreignKey: "employee_id",
      as: "trackinglocations",
    });

    /**
     * Associates the Employee model with the BloodGroup model.
     * Defines a many-to-one relationship between Employee and BloodGroup.
     * A Employee can only have one BloodGroup.
     * @param {object} models - The models to associate with.
     * @property {object} bloodgroup - The BloodGroup model associated with Employee.
     */
    Employee.belongsTo(models.BloodGroup, {
      foreignKey: "bloodgroup_id",
      as: "bloodgroup",
    });

    Employee.hasMany(models.UpCountry, {
      foreignKey: "employee_id",
      as: "upcountries",
    });

    Employee.hasMany(models.UcCostRealization, {
      foreignKey: "employee_id",
      as: "uccostrealizations",
    });

    Employee.hasMany(models.WorkActivity, {
      foreignKey: "employee_id",
      as: "workactivities",
    });

    Employee.belongsTo(models.User, { foreignKey: "modified_by", as: "modifier" });
  };

  return Employee;
};
