package com.bcxin.tenant.domain.services.impls;

import cn.hutool.core.date.DateUtil;
import com.bcxin.Infrastructures.ExceptionConstant;
import com.bcxin.Infrastructures.TenantContext;
import com.bcxin.Infrastructures.TenantUserContext;
import com.bcxin.Infrastructures.UnitWork;
import com.bcxin.Infrastructures.entities.OperatorValueType;
import com.bcxin.Infrastructures.enums.InvitedStatus;
import com.bcxin.Infrastructures.enums.InvitedType;
import com.bcxin.Infrastructures.exceptions.AbnormalPersonnelException;
import com.bcxin.Infrastructures.exceptions.BadTenantException;
import com.bcxin.Infrastructures.exceptions.NotFoundTenantException;
import com.bcxin.Infrastructures.exceptions.NotSupportTenantException;
import com.bcxin.Infrastructures.models.AbnormalPersonnelListDto;
import com.bcxin.Infrastructures.models.CredentialModel;
import com.bcxin.Infrastructures.utils.AuthUtil;
import com.bcxin.api.interfaces.identities.requests.InvitedToJoinQueuesRequest;
import com.bcxin.api.interfaces.security.AttendSitePersonRpcProvider;
import com.bcxin.api.interfaces.tenants.EmployeeRpcProvider;
import com.bcxin.api.interfaces.tenants.InviteAttendSiteRpcProvider;
import com.bcxin.api.interfaces.tenants.InviteDepartRpcProvider;
import com.bcxin.api.interfaces.tenants.requests.employees.EmployeeRequest;
import com.bcxin.api.interfaces.tenants.responses.InviteAttendSiteResponse;
import com.bcxin.api.interfaces.tenants.responses.InviteDepartResponse;
import com.bcxin.tenant.domain.entities.DepartmentEntity;
import com.bcxin.tenant.domain.entities.InvitedToJoinQueuesEntity;
import com.bcxin.tenant.domain.readers.TenantDbReader;
import com.bcxin.tenant.domain.readers.dtos.InvitedToJoinQueuesDto;
import com.bcxin.tenant.domain.repositories.DepartmentRepository;
import com.bcxin.tenant.domain.repositories.InvitedToJoinQueuesRepository;
import com.bcxin.tenant.domain.services.InvitedToJoinQueuesService;
import com.bcxin.tenant.domain.services.commands.InvitedToJoinQueuesCommand;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class InvitedToJoinQueuesServiceImpl implements InvitedToJoinQueuesService {

    private final InvitedToJoinQueuesRepository invitedToJoinQueuesRepository;

    private final InviteDepartRpcProvider inviteDepartRpcProvider;

    private final DepartmentRepository departmentRepository;

    private final InviteAttendSiteRpcProvider inviteAttendSiteRpcProvider;

    private final UnitWork unitWork;

    private final TenantDbReader dbReader;

    private final EmployeeRpcProvider employeeRpcProvider;

    private final AttendSitePersonRpcProvider attendSitePersonRpcProvider;

    public InvitedToJoinQueuesServiceImpl(InvitedToJoinQueuesRepository invitedToJoinQueuesRepository, InviteDepartRpcProvider inviteDepartRpcProvider,
                                          DepartmentRepository departmentRepository, InviteAttendSiteRpcProvider inviteAttendSiteRpcProvider, UnitWork unitWork, TenantDbReader dbReader,
                                          EmployeeRpcProvider employeeRpcProvider, AttendSitePersonRpcProvider attendSitePersonRpcProvider) {
        this.invitedToJoinQueuesRepository = invitedToJoinQueuesRepository;
        this.inviteDepartRpcProvider = inviteDepartRpcProvider;
        this.departmentRepository = departmentRepository;
        this.inviteAttendSiteRpcProvider = inviteAttendSiteRpcProvider;
        this.unitWork = unitWork;
        this.dbReader = dbReader;
        this.employeeRpcProvider = employeeRpcProvider;
        this.attendSitePersonRpcProvider = attendSitePersonRpcProvider;
    }

    @Override
    public void dispatch(InvitedToJoinQueuesCommand invitedToJoinQueuesCommand) {
        DepartmentEntity department = departmentRepository.findById(invitedToJoinQueuesCommand.getDepartmentId()).orElse(null);
        if(department==null || department.isDeleted()) {
            throw new NotFoundTenantException("该部门信息无效");
        }
        OperatorValueType operatorValueType = null;
        String organizationId = null;
        String attendanceSiteName = null;
        String attendanceSiteId = null;
        if (invitedToJoinQueuesCommand.getInvitedType() == InvitedType.InviteDepart) {
            InviteDepartResponse inviteDepart = inviteDepartRpcProvider.getUnOvertime(invitedToJoinQueuesCommand.getInviteId());
            if (inviteDepart == null) {
                throw new NotFoundTenantException("该邀请不存在或者已截止！");
            }

            if (!invitedToJoinQueuesCommand.getDepartmentId().equals(inviteDepart.getDepartId())) {
                throw new NotSupportTenantException("部门与邀请不符！");
            }

            if (!invitedToJoinQueuesCommand.getOccupationType().equals(inviteDepart.getOccupationType())) {
                throw new NotSupportTenantException("职业类型与邀请不符！");
            }
            operatorValueType = inviteDepart.getCreator();
            organizationId = inviteDepart.getOrganizationId();
        }else if(invitedToJoinQueuesCommand.getInvitedType() == InvitedType.InviteAttend){
            InviteAttendSiteResponse inviteAttendSite = inviteAttendSiteRpcProvider.getUnOvertime(invitedToJoinQueuesCommand.getInviteId());
            if (inviteAttendSite == null) {
                throw new NotFoundTenantException("该邀请不存在或者已截止！");
            }

            if (!invitedToJoinQueuesCommand.getDepartmentId().equals(inviteAttendSite.getDepartId())) {
                throw new NotSupportTenantException("部门与邀请不符！");
            }

            if (!invitedToJoinQueuesCommand.getOccupationType().equals(inviteAttendSite.getOccupationType())) {
                throw new NotSupportTenantException("职业类型与邀请不符！");
            }
            operatorValueType = inviteAttendSite.getCreator();
            organizationId = inviteAttendSite.getOrganizationId();
            attendanceSiteName = inviteAttendSite.getAttendSiteName();
            attendanceSiteId = inviteAttendSite.getAttendSiteId();
        }else{
            throw new NotSupportTenantException("邀请类型不符！");
        }
        AtomicReference<InvitedToJoinQueuesEntity> invitedAto = new AtomicReference<>();
        final OperatorValueType finalOperatorValueType = operatorValueType;
        final String finalOrganizationId = organizationId;
        final String finalAttendanceSiteName = attendanceSiteName;
        final String finalAttendanceSiteId = attendanceSiteId;
        this.unitWork.executeTran(() -> {
            invitedAto.set(
                    InvitedToJoinQueuesEntity.create(invitedToJoinQueuesCommand.getName(),
                            invitedToJoinQueuesCommand.getTelephone(), invitedToJoinQueuesCommand.getCredentialType(),
                            invitedToJoinQueuesCommand.getCredentialNumber(), finalOperatorValueType, invitedToJoinQueuesCommand.getInvitedType(),
                            invitedToJoinQueuesCommand.getDepartmentId(), department.getName(),
                            finalOrganizationId, invitedToJoinQueuesCommand.getOccupationType(),
                            finalAttendanceSiteName, finalAttendanceSiteId,
                            invitedToJoinQueuesCommand.getInvitedStatus(), invitedToJoinQueuesCommand.getLastOperatorId(),
                            invitedToJoinQueuesCommand.getLastOperatorName()));
            invitedToJoinQueuesRepository.save(invitedAto.get());
        });
    }

    @Override
    public void update(InvitedToJoinQueuesRequest request) {
        TenantUserContext.UserModel currentUser = TenantContext.getInstance().getUserContext().get();
        Collection<InvitedToJoinQueuesEntity> invitedToJoinQueuesEntities = this.invitedToJoinQueuesRepository.findByIds(request.getIds());
        StringBuffer exceptionMsg = new StringBuffer();
        Map<String, AbnormalPersonnelListDto> exceptionMap = new HashMap();
        for (InvitedToJoinQueuesEntity invitedToJoinQueuesEntity : invitedToJoinQueuesEntities) {
            try {
                if(InvitedStatus.Agree.equals(request.getInvitedStatus())) {
                    EmployeeRequest employeeRequest = new EmployeeRequest();
                    employeeRequest.setName(invitedToJoinQueuesEntity.getName());
                    employeeRequest.setTelephone(invitedToJoinQueuesEntity.getTelephone());
                    employeeRequest.setDepartId(invitedToJoinQueuesEntity.getDepartmentId());
                    employeeRequest.setCredential(CredentialModel.create(invitedToJoinQueuesEntity.getCredentialType(), invitedToJoinQueuesEntity.getCredentialNumber()));
                    employeeRequest.setPosition(null);
                    employeeRequest.setHiredDate(DateUtil.beginOfDay(new Date()));
                    employeeRequest.setOccupationType(invitedToJoinQueuesEntity.getOccupationType());
                    employeeRequest.setAbnormalPersonnelConfirm(request.getAbnormalPersonnelConfirm());
                    employeeRequest.setOperator(AuthUtil.getCurrentOperator());
                    String employeeId = this.employeeRpcProvider.create(invitedToJoinQueuesEntity.getOrganizationId(), employeeRequest);
                    if (InvitedType.InviteAttend.equals(invitedToJoinQueuesEntity.getInvitedType())) {
                        InviteAttendSiteResponse inviteAttendSite = new InviteAttendSiteResponse();
                        inviteAttendSite.setAttendSiteId(invitedToJoinQueuesEntity.getAttendanceSiteId());
                        inviteAttendSite.setDepartId(invitedToJoinQueuesEntity.getDepartmentId());
                        inviteAttendSite.setDepartName(invitedToJoinQueuesEntity.getDepartmentName());
                        inviteAttendSite.setOrganizationId(invitedToJoinQueuesEntity.getOrganizationId());
                        this.attendSitePersonRpcProvider.create(inviteAttendSite, employeeRequest, employeeId);
                    }
                }
                this.unitWork.executeTran(() -> {
                    invitedToJoinQueuesEntity.change(request.getInvitedStatus(),currentUser.getEmployeeId(),currentUser.getName());
                    this.invitedToJoinQueuesRepository.save(invitedToJoinQueuesEntity);
                });
            } catch (AbnormalPersonnelException e) {
                AbnormalPersonnelListDto dto = exceptionMap.get(e.getCode());
                if (dto == null) {
                    dto = new AbnormalPersonnelListDto();
                    dto.setCode(e.getCode());
                    if (ExceptionConstant.ABNORMAL_EMPLOYEE_REMIND_EXCEPTION_CODE.equals(e.getCode())) {
                        dto.setMsg("人员为从业异常人员，是否确认录用！");
                    } else {
                        dto.setMsg("人员不符合担任保安员，无法录入系统！");
                    }
                }
                dto.addId(invitedToJoinQueuesEntity.getId());
                exceptionMap.put(e.getCode(), dto);
            }
        }
        if (exceptionMap.size() > 0) {
            throw new AbnormalPersonnelException(ExceptionConstant.ABNORMAL_EMPLOYEE_BATCH_REMIND_EXCEPTION_CODE, "异常人员入职批量提醒", new ArrayList<>(exceptionMap.values()));
        }
    }
}
