package com.bcxin.tenant.domain.entities;

import com.bcxin.Infrastructures.entities.EntityAbstract;
import com.bcxin.Infrastructures.entities.IAggregate;
import com.bcxin.Infrastructures.enums.MasterSlaveType;
import com.bcxin.Infrastructures.utils.UUIDUtil;
import com.bcxin.tenant.domain.DomainConstraint;
import com.bcxin.tenant.domain.events.JoinDepartmentEvent;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.sql.Timestamp;
import java.time.Instant;

@Getter
@Setter(AccessLevel.PROTECTED)
@Table(name = "tenant_department_employee_relations",uniqueConstraints =
@UniqueConstraint(name = DomainConstraint.UNIQUE_DEPARTMENT_EMPLOYEE_RELATION_DEPARTMENT_EMPLOYEE,columnNames = {"department_id","employee_id"}))
@Entity
public class DepartmentEmployeeRelationEntity extends EntityAbstract implements IAggregate {

    @Id
    @Column(length = 100)
    private String id;

    @Column(name = "master_slave_type", nullable = false)
    @Enumerated(EnumType.ORDINAL)
    private MasterSlaveType masterSlaveType;

    @Column(name = "created_time", nullable = false)
    private Timestamp createdTime;

    public void gotoDepartment(DepartmentEntity destDepartment) {
        DepartmentEntity originalDepart = this.getDepartment();
        if (originalDepart.getId().equals(destDepartment.getId())) {
            return;
        }

        originalDepart.declEmployee();

        this.getEmployee().markDefaultDepartment(destDepartment);
        this.setDepartment(destDepartment);
        this.setDepartmentIndexTree(destDepartment.getIndexTree());
        destDepartment.incrEmployee();

        this.setMasterSlaveType(MasterSlaveType.Normal);
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.DETACH)
    @JoinColumn(name = "department_id", referencedColumnName = "id",
            foreignKey = @ForeignKey(name = "fk_department_employee_department_id", value = ConstraintMode.CONSTRAINT))
    private DepartmentEntity department;

    @Column(name = "department_index_tree")
    private String departmentIndexTree;

    @Column(name = "leader_type")
    private Boolean leaderType;

    /**
     * 如果设置value = ConstraintMode.CONSTRAINT
     * 需要确保EmployeeEntity一定比DepartmentEmployeeRelationEntity先持久化
     * 否则会报错
     *  java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`db_tenant2`.`tenant_department_employee_relations`,
     *  CONSTRAINT `fk_department_employee_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `tenant_employees` (`id`))
     */
    @ManyToOne(fetch = FetchType.LAZY,targetEntity = EmployeeEntity.class,cascade = CascadeType.DETACH)
    @OrderColumn
    @JoinColumn(name = "employee_id", referencedColumnName = "id",
            foreignKey = @ForeignKey(name = "fk_department_employee_employee_id", value = ConstraintMode.NO_CONSTRAINT))
    private EmployeeEntity employee;

    protected DepartmentEmployeeRelationEntity(){}

    public static DepartmentEmployeeRelationEntity create(
            DepartmentEntity department,
            EmployeeEntity employee,
            MasterSlaveType slaveType,
            boolean isNewEmployee) {

        DepartmentEmployeeRelationEntity departmentEmployeeRelation = new DepartmentEmployeeRelationEntity();

        departmentEmployeeRelation.setId(UUIDUtil.getShortUuid());
        departmentEmployeeRelation.setEmployee(employee);
        departmentEmployeeRelation.setDepartment(department);
        departmentEmployeeRelation.setDepartmentIndexTree(department.getIndexTree());
        departmentEmployeeRelation.setCreatedTime(Timestamp.from(Instant.now()));
        departmentEmployeeRelation.setMasterSlaveType(slaveType);

        if (!isNewEmployee) {
            departmentEmployeeRelation.recordEvent(JoinDepartmentEvent.create(
                    employee.getOrganization().getId(),
                    employee.getId(), department.getId()
            ));
        }

        return departmentEmployeeRelation;
    }
}
