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 },
			job_role: { type: DataTypes.STRING(100), allowNull: true },
			id_number: { type: DataTypes.BIGINT, allowNull: true },
			tax_number: { type: DataTypes.BIGINT, allowNull: true },
			npwp_number: { type: DataTypes.BIGINT, allowNull: true },
			npwp_address: { type: DataTypes.TEXT, allowNull: true },
			npwp_city_id: { type: DataTypes.INTEGER, allowNull: true },
			npwp_zip_code: { type: DataTypes.STRING(10), 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 },
			mother_maiden_name: { type: DataTypes.STRING(100), 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 },
			contract_status: { type: DataTypes.STRING(10), allowNull: true }, // PKWT | PKWTT
			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 },

			// Work from home rights
			eligible_for_wfh: { type: DataTypes.BOOLEAN, allowNull: true, defaultValue: false },

			// 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,
			},
			education_level_id: {
				type: DataTypes.INTEGER,
				allowNull: true,
			},
			placement_area_id: {
				type: DataTypes.INTEGER,
				allowNull: true,
			},
			secondary_placement_area_id: {
				type: DataTypes.INTEGER,
				allowNull: true,
			},
			zone_id: {
				type: DataTypes.INTEGER,
				allowNull: true,
			},
			recruitment_city_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,
			},
			team_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",
		});
		Employee.belongsTo(models.Team, {
			foreignKey: "team_id",
			as: "team",
		});

		Employee.belongsTo(models.JobRole, {
			foreignKey: "jobrole_id",
			as: "jobrole",
		});

		/**
		 * 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.belongsTo(models.EducationLevel, {
			foreignKey: "education_level_id",
			as: "education_level",
		});

		Employee.belongsTo(models.PlacementArea, {
			foreignKey: "placement_area_id",
			as: "placement_area",
		});

		Employee.belongsTo(models.PlacementArea, {
			foreignKey: "secondary_placement_area_id",
			as: "secondary_placement_area",
		});

		Employee.belongsTo(models.Zone, {
			foreignKey: "zone_id",
			as: "zone",
		});

		Employee.belongsTo(models.City, {
			foreignKey: "recruitment_city_id",
			as: "recruitment_city",
		});

		Employee.belongsTo(models.City, {
			foreignKey: "npwp_city_id",
			as: "npwp_city",
		});

		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;
};
