package com.kingdee.eas.custom.dormitorysystem.application.service;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.bsf.service.app.IHRMsfService;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.basedata.person.Genders;
import com.kingdee.eas.basedata.person.IPerson;
import com.kingdee.eas.basedata.person.PersonFactory;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.dormitorysystem.application.*;
import com.kingdee.eas.custom.dormitorysystem.dormitory.DormitoryCollection;
import com.kingdee.eas.custom.dormitorysystem.dormitory.DormitoryFactory;
import com.kingdee.eas.custom.dormitorysystem.dormitory.DormitoryInfo;
import com.kingdee.eas.custom.dormitorysystem.dormitory.IDormitory;
import com.kingdee.eas.custom.dormitorysystem.occupants.IOccupants;
import com.kingdee.eas.custom.dormitorysystem.occupants.OccupantsCollection;
import com.kingdee.eas.custom.dormitorysystem.occupants.OccupantsFactory;
import com.kingdee.eas.custom.dormitorysystem.occupants.OccupantsInfo;
import com.kingdee.eas.custom.dormitorysystem.otherbasicdata.PersonDormitoryTypeInfo;
import com.kingdee.eas.hr.ats.AtsUtil;
import com.kingdee.util.DateTimeUtils;
import com.kingdee.util.StringUtils;
import org.apache.log4j.Logger;

import java.util.*;

/**
 * @Description 根据入住日期和退宿日期获取可入住房间id
 * @Date 2025/4/27 16:06
 * @Created by Heyuan
 */
public class GetOptionalRoomIdsService implements IHRMsfService {
    private static Logger logger = Logger.getLogger(GetOptionalRoomIdsService.class);


    @Override
    public Object process(
            Context ctx,
            Map<String, Object> params
    ) throws EASBizException, BOSException {
        StringBuilder errorMsg = new StringBuilder();
        Set<String> dormitoryIdSet = new HashSet<String>();
        try {
            //入住日期
            String checkInDateStr = (String) params.get("checkInDate");
            if (StringUtils.isEmpty(checkInDateStr)) {
                throw new BOSException("入住日期不能为空!");
            }
            //退宿日期
            String checkoutDateStr = (String) params.get("checkoutDate");
            if (StringUtils.isEmpty(checkInDateStr)) {
                throw new BOSException("退宿日期不能为空!");
            }
            //人员id
            String personId = (String) params.get("personId");
            if (StringUtils.isEmpty(personId)) {
                throw new BOSException("人员id不能为空!");
            }
            //入住日期
            Date checkInDate = DateTimeUtils.parseDate(checkInDateStr, "yyyy-MM-dd");
            Date checkoutDate = DateTimeUtils.parseDate(checkoutDateStr, "yyyy-MM-dd");
            //根据入住日期,性别,员工类别查询可选房间
            IPerson iPerson = PersonFactory.getLocalInstance(ctx);
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("gender");
            sic.add("personType.*");
            sic.add("name");
            PersonInfo personInfo = iPerson.getPersonInfo(new ObjectUuidPK(personId), sic);
            Genders gender = personInfo.getGender();
            if (gender == null) {
                throw new BOSException("员工[" + personInfo.getName() + "]的性别为空，请及时维护！");
            }
            //人员类型
            PersonDormitoryTypeInfo personType = (PersonDormitoryTypeInfo) personInfo.get("personType");
            if (personType == null) {
                throw new BOSException("员工[" + personInfo.getName() + "]的人员类别为空，请及时维护！");
            }
            String personTypeId = personType.getId().toString();
            Map<String, Map<String, Object>> dormitoryMap = new HashMap<>();
            //存放已累加的人员入住信息数据id，避免重复累加
            //1.根据性别查询所有可住房间信息
            List<DormitoryInfo> dormitoryInfoList = getDormitoryInfos(ctx, gender, dormitoryIdSet);
            if (!dormitoryIdSet.isEmpty()) {
                //有可住房间信息
                //2.根据入住日期和退宿日期算出入住信息每个房间已住人数
                getCheckInInfoByOccupants(ctx, checkInDate, checkoutDate, dormitoryMap, dormitoryIdSet);
                //3.根据入住日期和退宿日期算出入住申请单状态为申请中的已住人数
                getCheckInInfoByCheckInApplication(ctx, checkInDate, checkoutDate, dormitoryMap, dormitoryIdSet);
                //4.根据入住日期和退宿日期算出换宿申请单状态为申请中的已住人数
                getRoomChangeInfoByRoomChangeApplication(ctx, checkInDate, checkoutDate, dormitoryMap, dormitoryIdSet);
                //5.算出房间剩余可住人数: 可住人数 - 已住人数
                for (int i = 0; i < dormitoryInfoList.size(); i++) {
                    DormitoryInfo dormitoryInfo = dormitoryInfoList.get(i);
                    String dormitoryId = dormitoryInfo.getId().toString();
                    Map<String, Object> dormCheckInMap = dormitoryMap.get(dormitoryId);
                    if (dormCheckInMap != null) {
                        String personDormitoryTypeId = (String) dormCheckInMap.getOrDefault("personDormitoryTypeId", "");
                        //判断是否宿舍类型跟人员类型是否相同
                        if (personDormitoryTypeId.equals(personTypeId)) {
                            //已住人数
                            int dormCheckInCount = (int) dormCheckInMap.get("count");
                            //可住人数
                            int occupancyCapacity = dormitoryInfo.getOccupancyCapacity();
                            if (occupancyCapacity - dormCheckInCount <= 0) {
                                dormitoryIdSet.remove(dormitoryId);
                            }
                        } else {
                            dormitoryIdSet.remove(dormitoryId);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e);
            errorMsg.append(e.getMessage()).append(System.lineSeparator());
        }
        Map result = new HashMap();
        if (errorMsg.length() > 0) {
            result.put("code", 500);
            result.put("errorMsg", errorMsg.toString());
        } else {
            result.put("code", 200);
            result.put("dormitoryIds", AtsUtil.convertSetToString(dormitoryIdSet));

        }
        return result;
    }


    /**
     * 根据入住日期和退宿日期算出换宿申请单状态为申请中的已住人数
     *
     * @param ctx
     * @param checkInDate    入住日期
     * @param checkoutDate   退宿日期
     * @param dormitoryMap
     * @param dormitoryIdSet 房间ids
     * @throws BOSException
     */
    private void getRoomChangeInfoByRoomChangeApplication(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            Map<String, Map<String, Object>> dormitoryMap,
            Set<String> dormitoryIdSet
    ) throws BOSException {
        IRoomChangeApplicationEntry iRoomChangeApplicationEntry = RoomChangeApplicationEntryFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //调整房间
        filterItems.add(new FilterItemInfo("adjustRoom", dormitoryIdSet, CompareType.INCLUDE));
        //申请入住日期在入住日期和退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.LESS_EQUALS));
        filterItems.add(new FilterItemInfo("checkoutDate", checkInDate, CompareType.GREATER_EQUALS));
        //入住日期在申请入住日期和申请退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.GREATER_EQUALS));
        filterItems.add(new FilterItemInfo("checkInDate", checkoutDate, CompareType.LESS_EQUALS));
        //单据状态等于未审批、审批中
        filterItems.add(new FilterItemInfo("parent.billState", "1,2", CompareType.INCLUDE));
        filterInfo.setMaskString("#0 and ((#1 and #2) or (#3 and #4)) and #5");
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("checkInRoom.id");
        sic.add("person.personType.id");
        sic.add("person.personType.name");
        sic.add("person.name");
        sic.add("occupants.id");
        sic.add("adjustRoom.id");
        sic.add("parent.number");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        RoomChangeApplicationEntryCollection roomChangeApplicationEntryCol = iRoomChangeApplicationEntry.getRoomChangeApplicationEntryCollection(viewInfo);
        for (int i = 0; i < roomChangeApplicationEntryCol.size(); i++) {
            RoomChangeApplicationEntryInfo roomChangeApplicationEntryInfo = roomChangeApplicationEntryCol.get(i);
            //房间
            PersonInfo person = roomChangeApplicationEntryInfo.getPerson();
            String personName = person.getName();
            //调整房间
            DormitoryInfo adjustRoom = roomChangeApplicationEntryInfo.getAdjustRoom();
            if (adjustRoom == null) {
                String number = roomChangeApplicationEntryInfo.getParent().getNumber();
                throw new BOSException("换宿单编码[" + number + "]中存在调整房间为空的数据，请检查换宿单数据正确性！");
            }
            String dormitoryId = adjustRoom.getId().toString();
            //人员类型
            PersonDormitoryTypeInfo personDormitoryType = (PersonDormitoryTypeInfo) person.get("personType");
            if (personDormitoryType == null) {
                throw new BOSException("员工[" + personName + "]的人员类别为空，请及时维护！");
            }
            if (dormitoryMap.containsKey(dormitoryId)) {
                Map<String, Object> map = dormitoryMap.get(dormitoryId);
                //累计已住人数
                int count = (int) map.getOrDefault("count", 0);
                map.put("count", count + 1);
            } else {
                Map<String, Object> map = new HashMap<>();
                map.put("count", 1);
                map.put("personDormitoryTypeId", personDormitoryType.getId().toString());
                dormitoryMap.put(dormitoryId, map);
            }
        }
    }

    /**
     * 根据入住日期和退宿日期算出入住申请单状态为申请中的已住人数
     *
     * @param ctx
     * @param checkInDate  入住日期
     * @param checkoutDate 退宿日期
     * @param dormitoryMap
     * @throws BOSException
     */
    private void getCheckInInfoByCheckInApplication(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            Map<String, Map<String, Object>> dormitoryMap,
            Set<String> dormitoryIdSet
    ) throws BOSException {
        ICheckInApplicationEntry iCheckInApplicationEntry = CheckInApplicationEntryFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间
        filterItems.add(new FilterItemInfo("checkInRoom", dormitoryIdSet, CompareType.INCLUDE));
        //申请入住日期在入住日期和退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.LESS_EQUALS));
        filterItems.add(new FilterItemInfo("checkoutDate", checkInDate, CompareType.GREATER_EQUALS));
        //入住日期在申请入住日期和申请退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.GREATER_EQUALS));
        filterItems.add(new FilterItemInfo("checkInDate", checkoutDate, CompareType.LESS_EQUALS));
        //单据状态为 未审批、审批中
        filterItems.add(new FilterItemInfo("parent.billState", "1,2", CompareType.INCLUDE));
        filterInfo.setMaskString("#0 and ((#1 and #2) or (#3 and #4)) and #5 ");
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("checkInRoom.id");
        sic.add("person.personType.id");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        CheckInApplicationEntryCollection checkInApplicationEntryCol = iCheckInApplicationEntry.getCheckInApplicationEntryCollection(viewInfo);
        for (int i = 0; i < checkInApplicationEntryCol.size(); i++) {
            CheckInApplicationEntryInfo checkInApplicationEntryInfo = checkInApplicationEntryCol.get(i);
            //房间
            DormitoryInfo checkInRoom = checkInApplicationEntryInfo.getCheckInRoom();
            String dormitoryId = checkInRoom.getId().toString();
            PersonInfo person = checkInApplicationEntryInfo.getPerson();
            String personName = person.getName();
            //人员类型
            PersonDormitoryTypeInfo personDormitoryType = (PersonDormitoryTypeInfo) person.get("personType");
            if (personDormitoryType == null) {
                throw new BOSException("员工[" + personName + "]的人员类别为空，请及时维护！");
            }
            if (dormitoryMap.containsKey(dormitoryId)) {
                Map<String, Object> map = dormitoryMap.get(dormitoryId);
                //累计已住人数
                int count = (int) map.getOrDefault("count", 0);
                map.put("count", count + 1);
            } else {
                Map<String, Object> map = new HashMap<>();
                map.put("count", 1);
                map.put("personDormitoryTypeId", personDormitoryType.getId().toString());
                dormitoryMap.put(dormitoryId, map);
            }
        }
    }

    /**
     * 根据入住日期和退宿日期算出入住信息中每个房间已住人数
     *
     * @param ctx
     * @param checkInDate    入住日期
     * @param checkoutDate   退宿日期
     * @param dormitoryIdSet
     * @return
     * @throws BOSException
     */
    protected void getCheckInInfoByOccupants(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            Map<String, Map<String, Object>> dormitoryMap,
            Set<String> dormitoryIdSet
    ) throws BOSException {
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间
        filterItems.add(new FilterItemInfo("Dormitory", dormitoryIdSet, CompareType.INCLUDE));
        //申请入住日期在入住日期和退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.LESS_EQUALS));
        filterItems.add(new FilterItemInfo("checkoutDate", checkInDate, CompareType.GREATER_EQUALS));
        //入住日期在申请入住日期和申请退宿日期之间
        filterItems.add(new FilterItemInfo("checkInDate", checkInDate, CompareType.GREATER_EQUALS));
        filterItems.add(new FilterItemInfo("checkInDate", checkoutDate, CompareType.LESS_EQUALS));
        filterInfo.setMaskString("#0 and ((#1 and #2) or (#3 and #4)) ");
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("Dormitory.id");
        sic.add("PersonDormitoryType.id");
        sic.add("person.personType.id");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        OccupantsCollection occupantsCollection = iOccupants.getOccupantsCollection(viewInfo);
        for (int i = 0; i < occupantsCollection.size(); i++) {
            OccupantsInfo occupantsInfo = occupantsCollection.get(i);
            //房间
            DormitoryInfo dormitory = occupantsInfo.getDormitory();
            String dormitoryId = dormitory.getId().toString();
            //人员宿舍分类
            PersonDormitoryTypeInfo personDormitoryType = (PersonDormitoryTypeInfo) occupantsInfo.getPerson().get("personType");
            if (dormitoryMap.containsKey(dormitoryId)) {
                Map<String, Object> map = dormitoryMap.get(dormitoryId);
                //累计已住人数
                int count = (int) map.getOrDefault("count", 0);
                map.put("count", count + 1);
            } else {
                Map<String, Object> map = new HashMap<>();
                map.put("count", 1);
                map.put("personDormitoryTypeId", personDormitoryType.getId().toString());
                dormitoryMap.put(dormitoryId, map);
            }
        }
    }

    /**
     * 查询所有可用房间信息
     *
     * @param ctx
     * @param gender 性别
     * @return
     * @throws BOSException
     */
    protected List<DormitoryInfo> getDormitoryInfos(Context ctx, Genders gender, Set<String> dormitoryIdSet) throws BOSException {
        IDormitory iDormitory = DormitoryFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间归类为房间
        filterItems.add(new FilterItemInfo("RoomClassification", 3));
        //宿舍类型.性别
        filterItems.add(new FilterItemInfo("DormitoryType.gender", gender.getValue()));
        filterItems.add(new FilterItemInfo("DormitoryType.gender", null));
        //状态为启用
        filterItems.add(new FilterItemInfo("state", "1"));
//        SelectorItemCollection sic = new SelectorItemCollection();
//        sic.add("Dormitory.id");
//        sic.add("PersonDormitoryType.id");
        filterInfo.setMaskString("#0 and (#1 or #2) and #3");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, null, null);
        //1.查询房间信息
        List<DormitoryInfo> dormitoryInfoList = new ArrayList<DormitoryInfo>();
        DormitoryCollection dormitoryCollection = iDormitory.getDormitoryCollection(viewInfo);
        for (int i = 0; i < dormitoryCollection.size(); i++) {
            DormitoryInfo dormitoryInfo = dormitoryCollection.get(i);
            dormitoryInfoList.add(dormitoryInfo);
            dormitoryIdSet.add(dormitoryInfo.getId().toString());
        }
        return dormitoryInfoList;
    }
}
