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

import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.bcxin.Infrastructures.commands.CommandAbstract;
import com.bcxin.Infrastructures.enums.CredentialType;
import com.bcxin.Infrastructures.enums.EmploymentStatus;
import com.bcxin.Infrastructures.enums.OccupationType;
import com.bcxin.Infrastructures.enums.Sex;
import com.bcxin.Infrastructures.exceptions.ArgumentTenantException;
import com.bcxin.Infrastructures.exceptions.TenantExceptionAbstract;
import com.bcxin.Infrastructures.utils.AuthUtil;
import com.bcxin.Infrastructures.utils.DateUtil;
import com.bcxin.Infrastructures.validations.CredentialValidator;
import com.bcxin.tenant.domain.entities.DepartmentEntity;
import com.bcxin.tenant.domain.readers.dtos.BatchEmployeeValidationDto;
import com.bcxin.tenant.domain.snapshots.EmployeeImportedItemSnapshot;
import com.bcxin.tenant.domain.configs.TenantUserConfig;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Getter
public class BatchImportEmployeeCommand extends CommandAbstract {
    private final String organizationId;
    private final String institutionalCode;
    private final String path;
    private final Collection<EmployeeCommandItem> commandItems;

    public BatchImportEmployeeCommand(String organizationId, String institutionalCode, String path, Collection<EmployeeCommandItem> commandItems) {
        this.organizationId = organizationId;
        this.institutionalCode = institutionalCode;
        this.path = path;
        this.commandItems = commandItems;
    }

    public Collection<String> getFormatDepartNames() {
        return this.commandItems.stream()
                .filter(ii -> ii.getDataItem() != null)
                .map(ii -> ii.getDepartName())
                .filter(ii -> StringUtils.hasLength(ii))
                .distinct()
                .collect(Collectors.toList());
    }

    public static BatchImportEmployeeCommand create(String organizationId, String institutionalCode, String path, Collection<EmployeeCommandItem> commandItems) {
        return new BatchImportEmployeeCommand(organizationId, institutionalCode, path, commandItems);
    }

    @Override
    public void validate() {
        validate(null);
    }

    public void validate(TenantUserConfig tenantUserConfig) {
        if (CollectionUtils.isEmpty(commandItems)) {
            throw new ArgumentTenantException("待导入的保安员列表不能为空");
        }

        commandItems.forEach(ix -> {
            try {
                ix.validate(tenantUserConfig);
            } catch (TenantExceptionAbstract ex) {
                ix.addError(ex.getMessage());
            }
        });
    }

    /*
    public void validateExist(List<BatchEmployeeValidationDto> employeeList, boolean requiredPhoneAsLoginName, String organizationId){
        if(employeeList == null || employeeList.size() == 0){
            return;
        }

        commandItems.forEach(ix -> {
            try {
                ix.setRequiredPhoneAsLoginName(requiredPhoneAsLoginName);
                ix.setOrganizationId(organizationId);
                if(requiredPhoneAsLoginName){
                    ix.validateExist(employeeList.stream().filter(i -> i.getTelephone().equals(ix.getDataItem().getTelephone())).collect(Collectors.toList()));
                }else {
                    ix.validateExist(employeeList.stream().filter(i -> i.getCredentialType() == ix.getCredentialType() &&
                            i.getCredentialNumber().equals(ix.getDataItem().getCredentialNumber())).collect(Collectors.toList()));
                }
            } catch (TenantExceptionAbstract ex) {
                ix.addError(ex.getMessage());
            }
        });

    }

     */

    @Getter
    public static class EmployeeCommandItem extends CommandAbstract {
        private final EmployeeImportedItemSnapshot dataItem;

        private boolean requiredPhoneAsLoginName = false;
        private String organizationId;
        private String institutionalCode;

        public void setRequiredPhoneAsLoginName(boolean requiredPhoneAsLoginName){
            this.requiredPhoneAsLoginName = requiredPhoneAsLoginName;
        }

        public void setOrganizationId(String organizationId){
            this.organizationId = organizationId;
        }

        public EmployeeCommandItem(EmployeeImportedItemSnapshot dataItem) {
            this.dataItem = dataItem;
        }

        public EmployeeCommandItem(EmployeeImportedItemSnapshot dataItem, String institutionalCode) {
            this.dataItem = dataItem;
            this.institutionalCode = institutionalCode;
        }

        public static EmployeeCommandItem create(String institutionalCode, int paramIndex, String name, String telephone, String departName,
                                                 String occupationTypeText, String positionText, String hiredDate,
                                                 String credentialTypeText, String credentialNumber, String nation,
                                                 String education, String politicsStatus, String militaryStatus, String maritalStatus,
                                                 String emergencyContact, String emergencyPhone, String address, String householdType) {
            return new EmployeeCommandItem(new EmployeeImportedItemSnapshot(paramIndex, name, telephone, departName,
                    occupationTypeText, positionText, hiredDate, credentialTypeText, credentialNumber, nation, education, politicsStatus, militaryStatus,
                    maritalStatus, emergencyContact, emergencyPhone, address, householdType), institutionalCode);
        }

        public static EmployeeCommandItem create(EmployeeImportedItemSnapshot snapshot) {
            return new EmployeeCommandItem(snapshot);
        }

        @JsonIgnore
        public OccupationType getOccupationType() {
            if(StrUtil.isEmpty(this.getDataItem().getOccupationTypeText())){
                return null;
            }
            switch (this.getDataItem().getOccupationTypeText()) {
                case "一般职员":
                    return OccupationType.Normal;
                case "保安员":
                    return OccupationType.SecurityGuard;
                case "警员":
                    return OccupationType.Police;
            }

            throw new ArgumentTenantException("职业类型无效");
        }

        @JsonIgnore
        public CredentialType getCredentialType() {
            if(StrUtil.isEmpty(this.getDataItem().getCredentialTypeText())){
                throw new ArgumentTenantException("证件类型无效");
            }

            if (StringUtils.hasLength(this.getDataItem().getCredentialTypeText())) {
                switch (this.getDataItem().getCredentialTypeText()) {
                    case "居民身份证（户口簿）":
                    case "居民身份证/户口簿":
                        return CredentialType.IdCard;
                    case "民警":
                    case "警号":
                        return CredentialType.PoliceNo;
                }
            }

            throw new ArgumentTenantException("证件类型无效");
        }

        @JsonIgnore
        public Collection<String> getFormattedDepartNames() {
            if (!StringUtils.hasLength(this.getDataItem().getDepartTreeName())) {
                return Collections.EMPTY_LIST;
            }

            return Arrays.stream(this.getDataItem().getDepartTreeName().split("/")).filter(ii -> !StringUtils.hasLength(ii))
                    .collect(Collectors.toList());
        }

        @JsonIgnore
        public String getDepartName() {
            if (!StringUtils.hasLength(this.getDataItem().getDepartTreeName())) {
                return null;
            }

            if (!this.getDataItem().getDepartTreeName().contains("/")) {
                return this.getDataItem().getDepartTreeName();
            }

            int lastIndex = this.getDataItem().getDepartTreeName().lastIndexOf("/");

            return this.getDataItem().getDepartTreeName().substring(lastIndex + 1);
        }

        @JsonIgnore
        public Date getHiredDate() {
            if (!StringUtils.hasLength(this.getDataItem().getHiredDateText())) {
                return null;
            }

            return DateUtil.fromString(this.getDataItem().getHiredDateText());
        }

        @Override
        public void validate() {
            validate(null);
        }

        public void validate(TenantUserConfig tenantUserConfig) {
            super.validate();

            checkParameter(() -> {
                if(StringUtils.hasLength(this.getDataItem().getEducation())) {
                    if (!this.getDataItem().getEducation().equals("初中") &&
                            !this.getDataItem().getEducation().equals("高中") &&
                            !this.getDataItem().getEducation().equals("中专") &&
                            !this.getDataItem().getEducation().equals("大专") &&
                            !this.getDataItem().getEducation().equals("本科") &&
                            !this.getDataItem().getEducation().equals("硕士研究生及以上")
                    ) {
                        throw new ArgumentTenantException("“文化程度”项不符合选项要求！");
                    }
                }
            });

            checkParameter(() -> {
                if (!StringUtils.hasLength(this.getDataItem().getName())) {
                    throw new ArgumentTenantException("姓名不能为空");
                }
            });

            checkParameter(() -> {
                if (!StringUtils.hasLength(this.getDataItem().getTelephone())) {
                    throw new ArgumentTenantException("手机号码不能为空");
                }
                if (!PhoneUtil.isPhone(this.getDataItem().getTelephone()) && !PhoneUtil.isTel(this.getDataItem().getTelephone())) {
                    throw new ArgumentTenantException("手机号码格式不正确");
                }
            });

            checkParameter(() -> {
                if (StringUtils.hasLength(this.getDataItem().getEmergencyPhone())) {
                    if (!PhoneUtil.isPhone(this.getDataItem().getEmergencyPhone()) && !PhoneUtil.isTel(this.getDataItem().getEmergencyPhone())) {
                        throw new ArgumentTenantException("紧急联系人电话格式不正确");
                    }
                }
            });

            if (this.isRequiredPhoneAsLoginName()) {
                checkParameter(() -> {
                    if (StrUtil.isEmpty(this.getDataItem().getCredentialNumber())) {
                        throw new ArgumentTenantException("证件号码不能为空");
                    }
                    if (StrUtil.isEmpty(this.getDataItem().getCredentialTypeText())) {
                        throw new ArgumentTenantException("证件类型不能为空");
                    }
                });
            }


            checkParameter(() -> {
                if (!StringUtils.hasLength(this.getDataItem().getHiredDateText())) {
                    throw new ArgumentTenantException("入职日期不能为空");
                }

                if (DateUtil.fromString(this.getDataItem().getHiredDateText()) == null) {
                    throw new ArgumentTenantException("入职日期不符合格式要求");
                }
                // 根据配置判断是否需要校验入职日期必须是当天
                if (tenantUserConfig != null && tenantUserConfig.isHiredDateMustBeToday() 
                    && !DateUtil.format2ShortDate().equals(DateUtil.format2ShortDate(this.getHiredDate()))) {
                    throw new ArgumentTenantException("入职日期必须是当天");
                }
            });

            checkParameter(() -> {
                if (!StringUtils.hasLength(this.getDataItem().getOccupationTypeText())) {
                    throw new ArgumentTenantException("职业类型不能为空");
                }
            });

            checkParameter(() -> {
                if (StringUtils.hasLength(this.getInstitutionalCode())
                        && (this.getInstitutionalCode().startsWith("04") || this.getInstitutionalCode().startsWith("06") || this.getInstitutionalCode().startsWith("07"))
                        && !this.getInstitutionalCode().endsWith("07") && !this.getInstitutionalCode().endsWith("08") && !this.getInstitutionalCode().endsWith("09")
                        && !StringUtils.hasLength(this.getDataItem().getPositionText())) {
                    //群防群治行业、内保行业、行业主管部门，且不是监管组织
                    throw new ArgumentTenantException("岗位不能为空");
                }
            });

            checkParameter(() -> {
                /**
                 * 用于验证有效的证件类型
                 */
                this.getCredentialType();
            });


            if(this.getOccupationType()!=null && this.getCredentialType()!=null) {
                checkParameter(() -> {
                    this.getOccupationType().validate(
                            this.getCredentialType(), this.getDataItem().getCredentialNumber(), AuthUtil.getAreaCode(), this.getInstitutionalCode());
                });
            }

            /**
             * 无效代码:
             * 目前导入的时候, 只允许的证件类型是身份证
             */
            if (OccupationType.SecurityGuard.equals(this.getOccupationType())) {
                //校验类型
                checkParameter(() -> {
                    CredentialType credentialType = this.getCredentialType();
                    if (CredentialType.IdCard != credentialType) {
                        throw new ArgumentTenantException("职业类型为保安员时, 证件类型类型必须为: 居民身份证/户口簿");
                    }
                });
            }
        }

        public DepartmentEntity validateDepartTree(Collection<DepartmentEntity> selectedDeparts) {
            AtomicReference<DepartmentEntity> matchedDepart = new AtomicReference<>();
            checkParameter(() -> {
                for (DepartmentEntity department : selectedDeparts) {
                    String expectedDepartTreeName = this.getDataItem().getDepartTreeName();
                    if ((department.getParent() == null && !StringUtils.hasLength(expectedDepartTreeName)) ||
                            department.getFullPath().equals(expectedDepartTreeName)) {
                        matchedDepart.set(department);
                        break;
                    }
                }

                if (matchedDepart.get() == null) {
                    throw new ArgumentTenantException(String.format("部门(%s)路径无效", this.getDataItem().getDepartTreeName()));
                }
            });

            return matchedDepart.get();
        }

        @Override
        public String toString() {
            return String.format("姓名=%s;部门=%s;入职日期=%s;职业=%s;证件类型=%s;证件号=%s;结果=%s;",
                    dataItem.getName(), dataItem.getDepartTreeName(), dataItem.getHiredDateText(),
                    dataItem.getOccupationTypeText(), dataItem.getCredentialTypeText(), dataItem.getCredentialNumber(),
                    this.getErrorResult());
        }
    }


}
