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

import com.kingdee.eas.custom.dormitorysystem.application.*;
import com.kingdee.eas.custom.dormitorysystem.enumerationset.DormitoryClassification;
import com.kingdee.eas.custom.dormitorysystem.otherbasicdata.DormitoryTypeInfo;
import com.kingdee.shr.base.syssetting.BasicItemStateEnum;
import org.apache.log4j.Logger;
import org.json.JSONArray;
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.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.util.DateTimeUtils;
import com.kingdee.util.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.*;

/**
 * @Description 校验房间是否入住(批量)
 * @Date 2025/4/27 17:00
 * @Created by Heyuan
 */
public class ValidateRoomAvailableService implements IHRMsfService {
    private static Logger logger = Logger.getLogger(ValidateRoomAvailableService.class);

    @Override
    public Object process(
            Context ctx,
            Map<String, Object> params
    ) throws EASBizException, BOSException {
        String validateDataStr = (String) params.get("validateData");
        if (StringUtils.isEmpty(validateDataStr)) {
            logger.error("校验数据不能为空!");
            throw new BOSException("校验数据不能为空!");
        }
        JSONArray validateDatas = null;
        try {
            validateDatas = new JSONArray(validateDataStr);
        } catch (JSONException e) {
            logger.error(e);
            throw new RuntimeException(e);
        }
        Map<String, List<Map<String, Date>>> roomListMap = new HashMap<String, List<Map<String, Date>>>();
        StringBuilder errorMsg = new StringBuilder();
        for (int i = 0; i < validateDatas.length(); i++) {
            try {
                JSONObject jsonObject = validateDatas.getJSONObject(i);
                //入住日期
                String checkInDateStr = jsonObject.getString("checkInDate");
                if (StringUtils.isEmpty(checkInDateStr)) {
                    throw new BOSException("入住日期不能为空!");
                }
                //退宿日期
                String checkoutDateStr = jsonObject.getString("checkoutDate");
                if (StringUtils.isEmpty(checkInDateStr)) {
                    throw new BOSException("退宿日期不能为空!");
                }
                //人员id
                String personId = jsonObject.getString("personId");
                if (StringUtils.isEmpty(personId)) {
                    throw new BOSException("人员id不能为空!");
                }
                //房间id
                String roomId = jsonObject.getString("roomId");
                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);
                //人员类型
                PersonDormitoryTypeInfo personType = (PersonDormitoryTypeInfo) personInfo.get("personType");
                if (personType == null) {
                    throw new BOSException("员工[" + personInfo.getName() + "]的人员类别为空，请及时维护！");
                }
                //String personTypeId = personType.getId().toString();
                //已住人数
                int dormCheckInCount = 0;
                //1.校验房间信息
                DormitoryInfo dormitoryInfo = validateDormitoryInfo(ctx, personInfo, roomId);
                //可住人数
                int occupancyCapacity = dormitoryInfo.getOccupancyCapacity();
                //2.根据入住日期和退宿日期算出入住信息房间已住人数
                dormCheckInCount += getCheckInInfoByOccupants(ctx, checkInDate, checkoutDate, roomId, personType);
                //3.根据入住日期和退宿日期算出入住申请单状态为申请中的已住人数
                dormCheckInCount += getCheckInInfoByCheckInApplication(ctx, checkInDate, checkoutDate, roomId,  personType);
                //4.根据入住日期和退宿日期算出换宿申请单状态为申请中的已住人数
                dormCheckInCount += getRoomChangeInfoByRoomChangeApplication(ctx, checkInDate, checkoutDate, roomId,  personType);
                //5.根据当前参数缓存算出已住人数
                if (roomListMap.containsKey(roomId)) {
                    List<Map<String, Date>> roomMapList = roomListMap.get(roomId);
                    for (int j = 0; j < roomMapList.size(); j++) {
                        Map<String, Date> roomMap = roomMapList.get(j);
                        Date checkInDateOld = roomMap.get("checkInDate");
                        Date checkoutDateOld = roomMap.get("checkoutDate");
                        //申请入住日期在入住日期和退宿日期之间
                        //入住日期在申请入住日期和申请退宿日期之间
                        if ((checkInDateOld.compareTo(checkInDate) <= 0 && checkoutDateOld.compareTo(checkInDate) >= 0)
                                || (checkInDateOld.compareTo(checkInDate) >= 0 && checkInDateOld.compareTo(checkoutDate) <= 0)) {
                            dormCheckInCount++;
                        }
                    }
                }
                //6.算出房间剩余可住人数: 可住人数 - 已住人数
                if (occupancyCapacity - dormCheckInCount < 0) {
                    String dormitoryName = dormitoryInfo.getName();
                    throw new BOSException("当前入住人数" + dormCheckInCount + "，已超过房间[" + dormitoryName + "]可住人数" + occupancyCapacity + "，不能入住!");
                }
                Map roomMap = new HashMap();
                roomMap.put("checkInDate", checkInDate);
                roomMap.put("checkoutDate", checkoutDate);
                if (roomListMap.containsKey(roomId)) {
                    roomListMap.get(roomId).add(roomMap);
                } else {
                    List list = new ArrayList();
                    roomListMap.put(roomId, list);
                    list.add(roomMap);
                }
            } 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);
        }
        return result;
    }


    /**
     * 根据入住日期和退宿日期算出换宿申请单状态为申请中的已住人数
     *
     * @param ctx
     * @param checkInDate  入住日期
     * @param checkoutDate 退宿日期
     * @param roomId       房间id
     * @param personType   人员类型
     * @return
     * @throws BOSException
     */
    private int getRoomChangeInfoByRoomChangeApplication(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            String roomId,
            PersonDormitoryTypeInfo personType
    ) throws BOSException {
        IRoomChangeApplicationEntry iRoomChangeApplicationEntry = RoomChangeApplicationEntryFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间
        filterItems.add(new FilterItemInfo("adjustRoom", roomId));
        //申请入住日期在入住日期和退宿日期之间
        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,3", 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");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        RoomChangeApplicationEntryCollection roomChangeApplicationEntryCol = iRoomChangeApplicationEntry.getRoomChangeApplicationEntryCollection(viewInfo);
        String personTypeId = personType.getId().toString();
        String personTypeName = personType.getName();
        //已住人数
        int dormCheckInCount = 0;
        for (int i = 0; i < roomChangeApplicationEntryCol.size(); i++) {
            RoomChangeApplicationEntryInfo roomChangeApplicationEntryInfo = roomChangeApplicationEntryCol.get(i);
            //房间
            PersonInfo person = roomChangeApplicationEntryInfo.getPerson();
            String personName = person.getName();
            //人员类型
            PersonDormitoryTypeInfo personDormitoryType = (PersonDormitoryTypeInfo) person.get("personType");
            if (personDormitoryType == null) {
                throw new BOSException("员工[" + personName + "]的人员类别为空，请及时维护！");
            }
            String personDormitoryTypeId = personDormitoryType.getId().toString();
            String personDormitoryTypeName = personDormitoryType.getName();
            if (!personTypeId.equals(personDormitoryTypeId)) {
                throw new BOSException("人员类别[" + personTypeName + "]与宿舍类型[" + personDormitoryTypeName + "]不符，不能入住！");
            }
            //累计已住人数
            dormCheckInCount++;
        }
        return dormCheckInCount;
    }

    /**
     * 根据入住日期和退宿日期算出入住申请单状态为申请中的已住人数
     *
     * @param ctx
     * @param checkInDate  入住日期
     * @param checkoutDate 退宿日期
     * @param roomId       房间id
     * @param personType   人员类型
     * @return
     * @throws BOSException
     */
    private int getCheckInInfoByCheckInApplication(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            String roomId,
            PersonDormitoryTypeInfo personType
    ) throws BOSException {
        ICheckInApplicationEntry iCheckInApplicationEntry = CheckInApplicationEntryFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间
        filterItems.add(new FilterItemInfo("checkInRoom", roomId));
        //申请入住日期在入住日期和退宿日期之间
        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,3", 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");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        CheckInApplicationEntryCollection checkInApplicationEntryCol = iCheckInApplicationEntry.getCheckInApplicationEntryCollection(viewInfo);
        String personTypeId = personType.getId().toString();
        String personTypeName = personType.getName();
        //已住人数
        int dormCheckInCount = 0;
        for (int i = 0; i < checkInApplicationEntryCol.size(); i++) {
            CheckInApplicationEntryInfo checkInApplicationEntryInfo = checkInApplicationEntryCol.get(i);
            //房间
            PersonInfo person = checkInApplicationEntryInfo.getPerson();
            String personName = person.getName();
            //人员类型
            PersonDormitoryTypeInfo personDormitoryType = (PersonDormitoryTypeInfo) person.get("personType");
            if (personDormitoryType == null) {
                throw new BOSException("员工[" + personName + "]的人员类别为空，请及时维护！");
            }
            String personDormitoryTypeId = personDormitoryType.getId().toString();
            String personDormitoryTypeName = personDormitoryType.getName();
            if (!personTypeId.equals(personDormitoryTypeId)) {
                throw new BOSException("人员类别[" + personTypeName + "]与宿舍类型[" + personDormitoryTypeName + "]不符，不能入住！");
            }
            //累计已住人数
            dormCheckInCount++;
        }
        return dormCheckInCount;
    }


    /**
     * 根据入住日期和退宿日期算出入住信息中每个房间已住人数
     *
     * @param ctx
     * @param checkInDate  入住日期
     * @param checkoutDate 退宿日期
     * @param roomId       房间id
     * @param personType   人员类型
     * @return
     * @throws BOSException
     */
    protected int getCheckInInfoByOccupants(
            Context ctx,
            Date checkInDate,
            Date checkoutDate,
            String roomId,
            PersonDormitoryTypeInfo personType
    ) throws BOSException {
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        //房间
        filterItems.add(new FilterItemInfo("Dormitory", roomId));
        //申请入住日期在入住日期和退宿日期之间
        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("PersonDormitoryType.id");
        sic.add("PersonDormitoryType.name");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
        OccupantsCollection occupantsCollection = iOccupants.getOccupantsCollection(viewInfo);
        String personTypeId = personType.getId().toString();
        String personTypeName = personType.getName();
        //已住人数
        int dormCheckInCount = 0;
        String personDormitoryTypeId = null;
        for (int i = 0; i < occupantsCollection.size(); i++) {
            OccupantsInfo occupantsInfo = occupantsCollection.get(i);
            //人员宿舍分类
            PersonDormitoryTypeInfo personDormitoryType = occupantsInfo.getPersonDormitoryType();
            personDormitoryTypeId = personDormitoryType.getId().toString();
            String personDormitoryTypeName = personDormitoryType.getName();
            if (!personTypeId.equals(personDormitoryTypeId)) {
                throw new BOSException("人员类别[" + personTypeName + "]与宿舍类型[" + personDormitoryTypeName + "]不符，不能入住！");
            }
            dormCheckInCount++;
        }
        return dormCheckInCount;
    }

    /**
     * 校验房间信息
     *
     * @param ctx
     * @param personInfo
     * @param roomIds    房间id
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    protected DormitoryInfo validateDormitoryInfo(
            Context ctx,
            PersonInfo personInfo,
            String roomIds
    ) throws BOSException, EASBizException {
        Genders gender = personInfo.getGender();
        if (gender == null) {
            throw new BOSException("员工性别为空!");
        }
        String personInfoName = personInfo.getName();
        IDormitory iDormitory = DormitoryFactory.getLocalInstance(ctx);
        //查询房间信息
        DormitoryInfo dormitoryInfo = iDormitory.getDormitoryInfo(new ObjectUuidPK(roomIds));
        String dormitoryName = dormitoryInfo.getName();
        DormitoryClassification roomClassification = dormitoryInfo.getRoomClassification();
        if (!DormitoryClassification.ROOM.equals(roomClassification)) {
            String classificationAlias = roomClassification.getAlias();
            throw new BOSException("房间[" + dormitoryName + "]房间归类为" + classificationAlias + "，不能入住!");
        }
        BasicItemStateEnum dormitoryInfoState = dormitoryInfo.getState();
        if (BasicItemStateEnum.DISABLE.equals(dormitoryInfoState)) {
            throw new BOSException("房间[" + dormitoryName + "]未启用，不能入住!");
        }
        //宿舍类型
        DormitoryTypeInfo dormitoryType = dormitoryInfo.getDormitoryType();
        Genders roomGender = dormitoryType.getGender();
        if (roomGender != null && gender.getValue() != roomGender.getValue()) {
            String dormitoryTypeName = dormitoryType.getName();
            throw new BOSException("房间[" + dormitoryName + "]宿舍类型为" + dormitoryTypeName + "，与人员[" + personInfoName + "]的性别不符!");
        }
        return dormitoryInfo;
    }
}
