package com.kingdee.eas.custom.compensation.startingsalary.backgroundtransaction;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.data.SortType;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.bos.util.BOSUuid;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.basedata.org.PositionInfo;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.certification.utils.DateUtil;
import com.kingdee.eas.custom.compensation.startingsalary.SalaryConfirmationCollection;
import com.kingdee.eas.custom.compensation.startingsalary.SalaryConfirmationFactory;
import com.kingdee.eas.custom.compensation.startingsalary.SalaryConfirmationInfo;
import com.kingdee.eas.framework.CoreBaseCollection;
import com.kingdee.eas.hr.affair.*;
import com.kingdee.eas.hr.base.HRBillStateEnum;
import com.kingdee.eas.hr.emp.SalaryItemFactory;
import com.kingdee.eas.hr.emp.SalaryItemInfo;
import com.kingdee.shr.recuritment.*;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 起薪核算后台事务控制器
 * <p>功能说明：入职业务单自动生成薪酬确认单业务逻辑</p>
 * <p>业务流程：查询已审核入职业务单 -> 根据身份证/护照匹配录用报批单 -> 校验录用报批薪酬分组数据 -> 自动生成薪酬确认单
 * 同时回填入职分录处理状态、异常信息</p>
 * @author
 * @date
 */
public class ConfirmationSalaryFacadeControllerBean extends AbstractConfirmationSalaryFacadeControllerBean {
    /**
     * 日志对象
     */
    private static Logger logger =
            Logger.getLogger("com.kingdee.eas.custom.compensation.startingsalary.backgroundtransaction.ConfirmationSalaryFacadeControllerBean");

    /**
     * 基础薪酬映射参数配置对象，存放薪酬分组编码、薪酬项目编码、薪酬字段映射关系
     */
    BasicSalaryParameters parameters = null;

//    public static void main(String[] args) {
//
//        try {
//            FilterInfo filterInfo = new FilterInfo();
//            filterInfo.getFilterItems().add(new FilterItemInfo("resumeBaseRec.identityCardNo", "sss", CompareType.EQUALS));
//
//            FilterInfo filterInfo1 = new FilterInfo();
//            filterInfo1.getFilterItems().add(new FilterItemInfo("resumeBaseRec.passportNo", "ccc", CompareType.EQUALS));
//
//
//            FilterInfo filterInfo3 = new FilterInfo();
//            filterInfo3.mergeFilter(filterInfo, "OR");
//            filterInfo3.mergeFilter(filterInfo1, "OR");
//            System.out.println(filterInfo3);
//
//        } catch (BOSException e) {
//            throw new RuntimeException(e);
//        }
//    }

    /**
     * 后台事务入口方法：根据条件查询入职业务单，自动生成薪酬确认单
     * @param ctx BOS上下文
     * @param employmentBill 入职业务单ID，多个使用英文逗号分隔；优先匹配该参数
     * @param leadDays 向前追溯天数；当单据ID为空时生效
     * @param startDate 自定义查询开始日期 yyyy-MM-dd；单据ID、追溯天数为空时生效
     * @param endDate 自定义查询结束日期 yyyy-MM-dd；单据ID、追溯天数为空时生效
     * @throws BOSException BOS平台异常
     */
    public void createBill(Context ctx, String employmentBill, int leadDays, String startDate, String endDate) throws BOSException {
        // 构建查询视图
        EntityViewInfo viewInfo = new EntityViewInfo();
        FilterInfo filterInfo = new FilterInfo();
        new BasicSalaryParameters(ctx);
        // 条件分支1：传入入职业务单ID集合，优先根据单据ID精确查询
        if (employmentBill != null && employmentBill.length() > 0) {
            employmentBill = employmentBill.trim();
            String[] split = employmentBill.split(",");
            // 去重存放单据ID
            Set<String> idSet = new HashSet<String>();
            for (String id : split) {
                idSet.add(id.trim());
            }
            filterInfo.getFilterItems().add(new FilterItemInfo("id", idSet, CompareType.INCLUDE));
        }
        // 条件分支2：未传入单据ID，使用向前追溯天数范围查询
        else if (leadDays != 0) {
            Date now = new Date();
            // 业务日期 <= 当前日期
            filterInfo.getFilterItems().add(new FilterItemInfo("bizDate", now, CompareType.LESS_EQUALS));
            // 计算追溯起始日期：当前日期向前推leadDays天
            Date before = DateUtil.add(now, -leadDays);
            // 业务日期 >= 追溯起始日期
            filterInfo.getFilterItems().add(new FilterItemInfo("bizDate", before, CompareType.GREATER_EQUALS));
            // 固定过滤条件：单据状态=已审核
            filterInfo.getFilterItems().add(new FilterItemInfo("billState", HRBillStateEnum.AUDITED_VALUE, CompareType.EQUALS));
            // 固定过滤条件：未生成薪酬确认单的记录
            filterInfo.getFilterItems().add(new FilterItemInfo("isSalaryConfirmation", false, CompareType.EQUALS));
        }
        // 条件分支3：未传入单据ID、追溯天数，使用自定义起止日期范围查询
        else if (startDate != null && startDate.length() > 0 && endDate != null && endDate.length() > 0) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date start = null;
            try {
                start = format.parse(startDate);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            Date end = null;
            try {
                end = format.parse(endDate);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            filterInfo.getFilterItems().add(new FilterItemInfo("bizDate", start, CompareType.GREATER_EQUALS));
            filterInfo.getFilterItems().add(new FilterItemInfo("bizDate", end, CompareType.LESS_EQUALS));
            // 固定过滤条件：单据状态=已审核
            filterInfo.getFilterItems().add(new FilterItemInfo("billState", HRBillStateEnum.AUDITED_VALUE, CompareType.EQUALS));
            // 固定过滤条件：未生成薪酬确认单的记录
            filterInfo.getFilterItems().add(new FilterItemInfo("isSalaryConfirmation", false, CompareType.EQUALS));
        }
        // 无有效查询条件，抛出异常
        else {
            throw new BOSException("请选择查询的日期范围");
        }

//        // 固定过滤条件：单据状态=已审核
//        filterInfo.getFilterItems().add(new FilterItemInfo("billState", HRBillStateEnum.AUDITED_VALUE, CompareType.EQUALS));
//        // 固定过滤条件：未生成薪酬确认单的记录
//        filterInfo.getFilterItems().add(new FilterItemInfo("isSalaryConfirmation", false, CompareType.EQUALS));
//
        viewInfo.setFilter(filterInfo);

        // 设置排序：业务日期倒序
        SorterItemCollection sorterItemCollection = new SorterItemCollection();
        SorterItemInfo sorterItemInfo = new SorterItemInfo();
        sorterItemInfo.setPropertyName("bizDate");
        sorterItemInfo.setSortType(SortType.DESCEND);
        sorterItemCollection.add(sorterItemInfo);
        viewInfo.setSorter(sorterItemCollection);

        // 查询字段：主表全部字段 + 分录全部字段
        SelectorItemCollection selectorItemCollection = new SelectorItemCollection();
        selectorItemCollection.add("*");
        selectorItemCollection.add("entrys.*");
        viewInfo.setSelector(selectorItemCollection);

        // 获取入职业务单远程实例并执行查询
        IEmpEnrollBizBill empEnrollBizBill = EmpEnrollBizBillFactory.getLocalInstance(ctx);
        EmpEnrollBizBillCollection empEnrollBizBillCollection = empEnrollBizBill.getEmpEnrollBizBillCollection(viewInfo);
        IEmpEnrollBizBillEntry enrollBizBillEntryFactory = EmpEnrollBizBillEntryFactory.getLocalInstance(ctx);

        // 循环遍历入职业务单主表
        for (int i = 0; i < empEnrollBizBillCollection.size(); i++) {
            EmpEnrollBizBillInfo empEnrollBizBillInfo = empEnrollBizBillCollection.get(i);
            EmpEnrollBizBillEntryCollection entrys = empEnrollBizBillInfo.getEntrys();
            // 循环遍历入职业务单分录
            for (int j = 0; j < entrys.size(); j++) {
                EmpEnrollBizBillEntryInfo entry = entrys.get(j);
                String idCardNo = entry.getIDCardNo();
                String passportNo = entry.getPassportNo();
                // 根据身份证号、护照号（or条件）查询录用报批单
                RecApprovalInfo recApprovalInfo = getRecApproval(ctx, idCardNo, passportNo);

                // 未查询到录用报批单：标记分录异常状态
                if (recApprovalInfo == null) {
                    try {
                        entry.put("isSalaryConfirmation", 0);
                        entry.put("isSuccess", 0);
                        entry.put("errorInfo", "通过 身份证："+idCardNo==null?"":idCardNo+" 护照："+passportNo==null?"":passportNo+" 查询录用报批单 未查到！！");
                        enrollBizBillEntryFactory.save(entry);
                    } catch (EASBizException e) {
                        e.printStackTrace();
                    }
                    continue;
                }

                // 获取录用报批薪酬分组信息
                RecBenefitGroupCollection group = recApprovalInfo.getGroup();
                // 校验薪酬分组、薪酬项目配置完整性
                Boolean b = checkSalaryData(ctx,group);
                if (!b) {
                    try {
                        entry.put("isSalaryConfirmation", 0);
                        entry.put("isSuccess", 0);
                        entry.put("errorInfo", "录用报批薪酬项目设置不符合！"+parameters.getRecBenefitNumber());
                        enrollBizBillEntryFactory.save(entry);
                    } catch (EASBizException e) {
                        e.printStackTrace();
                    }
                    continue;
                }

                // 校验通过，创建薪酬确认单
                try {
                    // 校验是薪酬确认单是否已经存在，如果已经存在则不处理

                    SalaryConfirmationCollection salaryConfirmationCollection = SalaryConfirmationFactory.getLocalInstance(ctx)
                            .getSalaryConfirmationCollection("where empEnrollEntry = '" + entry.getId() + "'");
                    if (salaryConfirmationCollection.size() > 0) {
                        entry.put("isSalaryConfirmation", 1);
                        entry.put("isSuccess", 1);
                        entry.put("errorInfo", "已创建薪酬确认单！无法在创建！");
                        enrollBizBillEntryFactory.save(entry);
                        continue;
                    }


                    writeSalaryConfirm(ctx,group, recApprovalInfo, entry);
                }catch (Exception e){
                    e.printStackTrace();
                    // 创建薪酬确认单异常，回填错误信息至分录
                    try {
                        entry.put("isSalaryConfirmation", 0);
                        entry.put("isSuccess", 0);
                        entry.put("errorInfo", "创建薪酬确认单失败！"+e.getMessage());
                        enrollBizBillEntryFactory.save(entry);
                    } catch (EASBizException k) {
                        k.printStackTrace();
                    }
                    continue;
                }

                // 创建成功，更新分录状态
                entry.put("isSalaryConfirmation", 1);
                entry.put("isSuccess", 1);
                entry.put("errorInfo", "");
                try {
                    enrollBizBillEntryFactory.save(entry);
                } catch (EASBizException e) {
                    e.printStackTrace();
                }

            }
            // 更新入职业务单主表标记：已执行薪酬确认生成
            try {
                empEnrollBizBillInfo.put("isSalaryConfirmation",1);
                CoreBaseCollection coreBaseCollection = new CoreBaseCollection();
                coreBaseCollection.add(empEnrollBizBillInfo);
                empEnrollBizBill.update(coreBaseCollection);
            } catch (EASBizException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 组装并保存薪酬确认单
     * @param context BOS上下文
     * @param group 录用报批薪酬分组集合
     * @param recApprovalInfo 录用报批单信息
     * @param entryInfo 入职业务分录信息
     */
    private void writeSalaryConfirm(Context context,RecBenefitGroupCollection group,RecApprovalInfo recApprovalInfo , EmpEnrollBizBillEntryInfo entryInfo) {
        System.out.println("开始写入薪酬确认单！");
        // 获取薪酬项目与实体字段映射关系
        Map<String, Map<String, String>> transferSalary = parameters.getTransferSalary();
        SalaryConfirmationInfo salaryConfirmationInfo = new SalaryConfirmationInfo();

        // 基础组织人员信息赋值
        AdminOrgUnitInfo adminOrg = entryInfo.getAdminOrg();
        salaryConfirmationInfo.setAdminOrg(adminOrg);
        PositionInfo position = entryInfo.getPosition();
        salaryConfirmationInfo.setPosition(position);
        PersonInfo person = entryInfo.getPerson();
        salaryConfirmationInfo.setPerson(person);
        // 关联入职业务分录
        salaryConfirmationInfo.setEmpEnrollEntry(entryInfo);

        // 遍历薪酬分组
        for (int i = 0; i < group.size(); i++) {
            RecBenefitGroupInfo recBenefitGroupInfo = group.get(i);
            System.out.println("分组信息："+recBenefitGroupInfo);
            String number = recBenefitGroupInfo.getNumber();
            RecBenefitCollection recBenefit = recBenefitGroupInfo.getRecBenefit();
            // 获取当前分组下薪酬项目对应的实体字段映射
            Map<String, String> stringStringMap = transferSalary.get(number);
            System.out.println("分组编号："+number);
            System.out.println("分组映射："+stringStringMap);
            // 遍历分组内薪酬项目
            for (int j = 0; j < recBenefit.size(); j++) {
                RecBenefitInfo recBenefitInfo = recBenefit.get(j);
                String amount = recBenefitInfo.getAmount();
                SalaryItemInfo salaryItem = recBenefitInfo.getSalaryItem();
                // 根据薪酬项目编码获取目标字段名
                String number1 = salaryItem.getNumber();
                if (number1 == null) {
                    try {
                        salaryItem = SalaryItemFactory.getLocalInstance(context)
                                .getSalaryItemInfo(new ObjectUuidPK(salaryItem.getId()));
                        System.out.println("获取薪酬项目信息："+salaryItem);
                        number1 = salaryItem.getNumber();
                    } catch (BOSException e) {
                        e.printStackTrace();
                    } catch (EASBizException e) {
                        e.printStackTrace();
                    }
                }
                String key = stringStringMap.get(number1);
                System.out.println("映射关系："+number1+"-->"+key);
                // 动态给薪酬确认单对应字段赋值
                System.out.println("字段名："+key+" 值："+amount);
                salaryConfirmationInfo.put(key,new BigDecimal(amount));
            }
        }

        // 关联录用报批单、默认设置单据为已审核状态并保存
        try {
            salaryConfirmationInfo.setRecApproval(recApprovalInfo);
            salaryConfirmationInfo.setBillState(HRBillStateEnum.AUDITED);
            SalaryConfirmationFactory.getLocalInstance(context).save(salaryConfirmationInfo);
        } catch (BOSException e) {
            throw new RuntimeException(e);
        } catch (EASBizException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 校验录用报批薪酬分组数据合法性
     * <p>校验规则：分组数量、分组编码、分组内薪酬项目数量、薪酬项目编码与配置参数匹配</p>
     * @param group 录用报批薪酬分组集合
     * @return true=校验通过；false=校验不通过
     */
    private Boolean checkSalaryData(Context context,RecBenefitGroupCollection group) {
        System.out.println("开始校验分组数据！");
        System.out.println("分组数据：" + group);

        // 获取配置文件预设薪酬分组编码数组
        String recBenefitGroupNumber = parameters.getRecBenefitGroupNumber();
        String[] split = recBenefitGroupNumber.split(",");
        // 校验分组总数是否匹配配置
        if (group.size() != split.length) {
            System.out.println("分组数量不匹配！");
            return false;
        }

        // 获取预设薪酬项目编码数组
        String recBenefitNumber = parameters.getRecBenefitNumber();
        String[] split1 = recBenefitNumber.split(",");

        // 循环校验每一个薪酬分组
        for (int i = 0; i < group.size(); i++) {
            RecBenefitGroupInfo recBenefitGroupInfo = group.get(i);
            String number = recBenefitGroupInfo.getNumber();
            // 校验当前分组编码是否在配置清单内
            if (recBenefitGroupNumber.indexOf(number) < 0) {
                System.out.println("分组编码不对！"+number+" 配置编码为:"+recBenefitGroupNumber);
                return false;
            }
            RecBenefitCollection recBenefit = recBenefitGroupInfo.getRecBenefit();
            // 校验分组内薪酬项目数量与配置一致
//            if (recBenefit.size() != split1.length) {
//                System.out.println("分组内薪酬项目数量不对！"+number+" 分组内项目数量为:"+recBenefit.size()+" 配置项目数量为:"+split1.length);
//                return false;
//            }
            // 循环校验分组内薪酬项目
            for (int j = 0; j < recBenefit.size(); j++) {
                RecBenefitInfo recBenefitInfo = recBenefit.get(j);
                SalaryItemInfo salaryItem = recBenefitInfo.getSalaryItem();
                String salaryItemNumber = salaryItem.getNumber();
                if (salaryItemNumber == null) {
                    try {
                        BOSUuid id = recBenefitInfo.getId();
                        salaryItem = SalaryItemFactory.getLocalInstance(context).getSalaryItemInfo(new ObjectUuidPK(id));
                        salaryItemNumber = salaryItem.getNumber();
                    } catch (BOSException e) {
                        e.printStackTrace();
                    } catch (EASBizException e) {
                        e.printStackTrace();
                    }
                }
                // 校验薪酬项目编码是否在配置清单内
                if (recBenefitNumber.indexOf(salaryItemNumber) < 0) {
                    System.out.println("薪酬项目编码不对！"+salaryItemNumber+" 配置编码为:"+recBenefitNumber);
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 通过身份证号、护照号【或条件】查询录用报批单
     * 优先匹配身份证，无匹配则匹配护照，取最新创建的第一条录用报批单
     * @param context BOS上下文
     * @param idCardNo 身份证号码
     * @param passportNo 护照号码
     * @return 匹配成功返回录用报批单；无数据返回null
     */
    public RecApprovalInfo getRecApproval(Context context, String idCardNo, String passportNo) {
        EntityViewInfo viewInfo = new EntityViewInfo();
        try {
            // 身份证查询条件
            FilterInfo filterInfo = new FilterInfo();
            filterInfo.getFilterItems().add(new FilterItemInfo("resumeBaseRec.identityCardNo", idCardNo, CompareType.EQUALS));
            // 护照查询条件
            FilterInfo filterInfo1 = new FilterInfo();
            filterInfo1.getFilterItems().add(new FilterItemInfo("resumeBaseRec.passportNo", passportNo, CompareType.EQUALS));
            // OR合并两组查询条件
            FilterInfo filterInfo3 = new FilterInfo();
            filterInfo3.mergeFilter(filterInfo, "OR");
            filterInfo3.mergeFilter(filterInfo1, "OR");
            viewInfo.setFilter(filterInfo3);
        } catch (BOSException e) {
            throw new RuntimeException(e);
        }

        // 指定需要抓取的关联字段：简历基础信息、薪酬分组、薪酬项目、薪酬基础资料
        SelectorItemCollection selectorItemCollection = new SelectorItemCollection();
        selectorItemCollection.add("*");
        selectorItemCollection.add("resumeBaseRec.*");
        selectorItemCollection.add("resumeBaseRec.resumeBaseInfo.*");
        selectorItemCollection.add("group.*");
        selectorItemCollection.add("group.RecBenefit.*");
        selectorItemCollection.add("group.RecBenefit.salaryItem.*");
        viewInfo.setSelector(selectorItemCollection);

        // 创建时间倒序，优先取最新单据
        SorterItemCollection sorterItemCollection = new SorterItemCollection();
        SorterItemInfo sorterItemInfo = new SorterItemInfo("resumeBaseRec.CreateTime");
        sorterItemInfo.setSortType(SortType.DESCEND);
        sorterItemCollection.add(sorterItemInfo);
        viewInfo.setSorter(sorterItemCollection);

        try {
            System.out.println("查询条件 viewInfo："+viewInfo);
            IRecApproval recApproval = RecApprovalFactory.getLocalInstance(context);
            RecApprovalCollection recApprovalCollection = recApproval
                    .getRecApprovalCollection(viewInfo);
            // 查询到数据返回第一条
            if (recApprovalCollection.size() > 0) {
                return recApprovalCollection.get(0);
            }
        } catch (BOSException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
}