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

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.IObjectValue;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
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.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.dormitorysystem.application.*;
import com.kingdee.eas.custom.dormitorysystem.application.utils.CheckDuplicateCheckInByBillIdUtil;
import com.kingdee.eas.custom.dormitorysystem.application.utils.ValidateRoomAvailableByBillIdsUtil;
import com.kingdee.eas.custom.dormitorysystem.dormitory.DormitoryInfo;
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.framework.CoreBaseCollection;
import com.kingdee.eas.framework.CoreBaseInfo;
import com.kingdee.eas.hr.affair.AffairBizException;
import com.kingdee.eas.hr.base.HRBaseException;
import com.kingdee.eas.hr.base.HRBillBaseInfo;
import com.kingdee.eas.hr.base.HRBillStateEnum;
import com.kingdee.shr.base.syssetting.BaseItemException;
import com.kingdee.shr.base.syssetting.IMSFServiceFacade;
import com.kingdee.shr.base.syssetting.MSFServiceFacadeFactory;
import com.kingdee.util.StringUtils;
import org.apache.log4j.Logger;

import java.text.SimpleDateFormat;
import java.util.*;

public class CheckoutApplicationControllerBean extends AbstractCheckoutApplicationControllerBean {
    private static Logger logger = Logger.getLogger(CheckoutApplicationControllerBean.class);

    /**
     * 校验单据（流程中使用）
     *
     * @param ctx
     * @param billID
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected boolean _validateBillInProcess(
            Context ctx,
            BOSUuid billID
    ) throws BOSException, EASBizException {
        boolean isError = super._validateBillInProcess(ctx, billID);
        if (!isError) {
            if (billID == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"单据id不能为空!"});
            }
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("*");
            sic.add("entrys.*");
            sic.add("entrys.occupants.*");
            //校验单据
            CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billID), sic);
            try {
                HRBillStateEnum billState = info.getBillState();
                if (HRBillStateEnum.AUDITED.equals(billState)) {
                    throw new BOSException("单据已经审批通过，请勿重复操作！");
                }
                IRoomChangeApplicationEntry iRoomChangeApplicationEntry = RoomChangeApplicationEntryFactory.getLocalInstance(ctx);
                CheckoutApplicationEntryCollection entrys = info.getEntrys();
                for (int i = 0; i < entrys.size(); i++) {
                    CheckoutApplicationEntryInfo entryInfo = entrys.get(i);
                    OccupantsInfo occupants = entryInfo.getOccupants();
                    if (occupants == null) {
                        throw new BOSException("入住信息为空!");
                    }
                    String personName = entryInfo.getPerson().getName();
                    //校验入住信息是否被换宿
                    RoomChangeApplicationEntryCollection roomChangeApplicationEntryCollection =
                            iRoomChangeApplicationEntry.getRoomChangeApplicationEntryCollection("select parent.number where oldOccupants = '" + occupants.getId() + "'");
                    if (roomChangeApplicationEntryCollection.size() > 0) {
                        RoomChangeApplicationEntryInfo roomChangeApplicationEntryInfo = roomChangeApplicationEntryCollection.get(0);
                        String number = roomChangeApplicationEntryInfo.getParent().getNumber();
                        throw new BOSException("员工 " + personName + "已有换宿单[ " + number + " ]，不能提交生效！\n");
                    }
                }
            } catch (Exception e) {
                logger.error(e);
                SelectorItemCollection updateSic = new SelectorItemCollection();
                sic.add("errorMsg");
                //设置校验信息
                info.setErrorMsg(e.getMessage());
                updatePartial(ctx, info, updateSic);
                return true;
            }
        }
        return isError;
    }


    @Override
    protected void _setSubmited(Context ctx, BOSUuid billID) throws BOSException, EASBizException {
        super._setSubmited(ctx, billID);
        //清空错误信息
        CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billID));
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("errorMsg");
        //设置校验信息
        info.setErrorMsg(null);
        updatePartial(ctx, info, sic);
    }


    @Override
    protected void _setAuditing(Context ctx, BOSUuid billID) throws BOSException, EASBizException {
        super._setAuditing(ctx, billID);
        //清空错误信息
        CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billID));
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("errorMsg");
        //设置校验信息
        info.setErrorMsg(null);
        updatePartial(ctx, info, sic);
    }

    /**
     * 设置申请通过
     * 流程中调用
     *
     * @param ctx
     * @param billID
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _setAudited(Context ctx, BOSUuid billID) throws BOSException, EASBizException {
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("entrys.*");
        sic.add("entrys.occupants.*");
        //校验单据
        CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billID), sic);
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        CoreBaseCollection updateCols = new CoreBaseCollection();
        CheckoutApplicationEntryCollection entrys = info.getEntrys();
        for (int i = 0; i < entrys.size(); i++) {
            CheckoutApplicationEntryInfo entryInfo = entrys.get(i);
            Date checkoutDate = entryInfo.getCheckoutDate();
            OccupantsInfo occupants = entryInfo.getOccupants();
            occupants.setCheckOutDate(checkoutDate);
            updateCols.add(occupants);
        }
        //批量更新入住信息
        iOccupants.updateBatchData(updateCols);
        super._setAudited(ctx, billID);
    }


    @Override
    protected IObjectPK _save(Context ctx, IObjectValue model) throws BOSException, EASBizException {
        //退宿单
        CheckoutApplicationInfo info = (CheckoutApplicationInfo) model;
        //退宿单分录
        CheckoutApplicationEntryCollection entrys = info.getEntrys();
        Set<String> occupantsIds = new HashSet<String>();
        ICheckoutApplicationEntry iCheckoutApplicationEntry = CheckoutApplicationEntryFactory.getLocalInstance(ctx);
        for (int i = 0; i < entrys.size(); i++) {
            CheckoutApplicationEntryInfo checkoutApplicationEntryInfo = entrys.get(i);
            BOSUuid id = checkoutApplicationEntryInfo.getId();
            //入住人员信息
            OccupantsInfo occupants = checkoutApplicationEntryInfo.getOccupants();
            if (occupants == null) {
                throw new BOSException("入住人员信息不能为空!");
            }
            String occupantsId = occupants.getId().toString();
            if (occupantsIds.contains(occupantsId)) {
                throw new BOSException("本单据中存在对相同入住信息做退宿情况，请检查单据信息！");
            }
            occupantsIds.add(occupantsId);
            //校验是否存在对相同入住信息对退宿的退宿单分录
            FilterInfo filterInfo = new FilterInfo();
            FilterItemCollection filterItems = filterInfo.getFilterItems();
            filterItems.add(new FilterItemInfo("occupants", occupantsId));
            if (id != null) {
                filterItems.add(new FilterItemInfo("id", id, CompareType.NOTEQUALS));
            }
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("person.name");
            sic.add("occupants.number");
            sic.add("parent.number");
            EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
            CheckoutApplicationEntryCollection checkoutApplicationEntryCol = iCheckoutApplicationEntry.getCheckoutApplicationEntryCollection(viewInfo);
            for (int j = 0; j < checkoutApplicationEntryCol.size(); j++) {
                CheckoutApplicationEntryInfo checkoutApplicationEntry = checkoutApplicationEntryCol.get(j);
                String personName = checkoutApplicationEntry.getPerson().getName();
                String occupantsNumber = checkoutApplicationEntry.getOccupants().getNumber();
                String number = checkoutApplicationEntry.getParent().getNumber();
                throw new BOSException(personName + "的入住信息[" + occupantsNumber + "]已经在退宿单[" + number + "]，请勿重复提交退宿单！");
            }
        }
        return super._save(ctx, model);
    }

    /**
     * 删除
     *
     * @param ctx
     * @param pk
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _delete(Context ctx, IObjectPK pk) throws BOSException, EASBizException {
        HRBillBaseInfo info = (HRBillBaseInfo) this._getValue(ctx, pk);
        HRBillStateEnum billState = info.getBillState();
        boolean isRemovable = true;
        //已提交、审批中、审批通过的单据不允许删除
        if (HRBillStateEnum.SUBMITED.equals(billState)
                || HRBillStateEnum.AUDITING.equals(billState)
                || HRBillStateEnum.AUDITED.equals(billState)) {
            isRemovable = false;
        }
        if (!isRemovable) {
            throw new AffairBizException(AffairBizException.BILLCANTDELETE);
        }
        super._delete(ctx, pk);
    }


    /**
     * 提交生效
     *
     * @param ctx
     * @param billId
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected IObjectPK _submitEffect(Context ctx, String billId) throws BOSException, EASBizException {
        if (StringUtils.isEmpty(billId)) {
            throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"单据id不能为空!"});
        }
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("*");
        sic.add("entrys.*");
        sic.add("entrys.occupants.*");
        //校验单据
        CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billId), sic);
        HRBillStateEnum billState = info.getBillState();
        if (HRBillStateEnum.AUDITED.equals(billState)) {
            throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"单据已经审批通过，请勿重复操作！"});
        }
        IRoomChangeApplicationEntry iRoomChangeApplicationEntry = RoomChangeApplicationEntryFactory.getLocalInstance(ctx);
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        CoreBaseCollection updateCols = new CoreBaseCollection();
        CheckoutApplicationEntryCollection entrys = info.getEntrys();
        for (int i = 0; i < entrys.size(); i++) {
            CheckoutApplicationEntryInfo entryInfo = entrys.get(i);
            Date checkoutDate = entryInfo.getCheckoutDate();
            OccupantsInfo occupants = entryInfo.getOccupants();
            if (occupants == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"入住信息为空!"});
            }
            String personName = entryInfo.getPerson().getName();
            //校验入住信息是否被换宿
            RoomChangeApplicationEntryCollection roomChangeApplicationEntryCollection =
                    iRoomChangeApplicationEntry.getRoomChangeApplicationEntryCollection("select parent.number where oldOccupants = '" + occupants.getId() + "'");
            if (roomChangeApplicationEntryCollection.size() > 0) {
                RoomChangeApplicationEntryInfo roomChangeApplicationEntryInfo = roomChangeApplicationEntryCollection.get(0);
                String number = roomChangeApplicationEntryInfo.getParent().getNumber();
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"员工 " + personName + "已有换宿单[ " + number + " ]，不能提交生效！\n"});
            }
            occupants.setCheckOutDate(checkoutDate);
            updateCols.add(occupants);
        }
        //批量更新入住信息
        iOccupants.updateBatchData(updateCols);
        //提交生效
        IObjectPK iObjectPK = super._submitEffect(ctx, info);
        return iObjectPK;
    }

    /**
     * 提交生效
     *
     * @param ctx
     * @param model
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected IObjectPK _submitEffect(
            Context ctx,
            CoreBaseInfo model
    ) throws BOSException, EASBizException {
        String billId = model.getId().toString();
        return _submitEffect(ctx, billId);
    }

    /**
     * 反审批单据
     *
     * @param ctx
     * @param billId
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _untiCheckBizBill(
            Context ctx,
            String billId
    ) throws BOSException, EASBizException {
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("*");
        sic.add("entrys.*");
        sic.add("entrys.person.*");
        sic.add("entrys.occupants.*");
        sic.add("entrys.currentRoom.*");
        CheckoutApplicationInfo info = getCheckoutApplicationInfo(ctx, new ObjectUuidPK(billId), sic);
        HRBillStateEnum billState = info.getBillState();
        if (!HRBillStateEnum.AUDITED.equals(billState)) {
            throw new AffairBizException(HRBaseException.BILLSTATECANUNCHECK);
        }
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        CheckoutApplicationEntryCollection entrys = info.getEntrys();
        CoreBaseCollection updateCols = new CoreBaseCollection();
        for (int i = 0; i < entrys.size(); i++) {
            //退宿单分录
            CheckoutApplicationEntryInfo entryInfo = entrys.get(i);
            PersonInfo person = entryInfo.getPerson();
            String personId = person.getId().toString();
            //入住日期
            Date checkInDate = entryInfo.getCheckInDate();
            if (checkInDate == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"入住日期为空!"});
            }
            //原退宿日期
            Date oldCheckoutDate = entryInfo.getOldCheckoutDate();
            if (oldCheckoutDate == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"原退宿日期为空!"});
            }
            OccupantsInfo occupants = entryInfo.getOccupants();
            if (occupants == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"入住信息为空!"});
            }
            //String occupantsId = occupants.getId().toString();
            //现住房间
            DormitoryInfo currentRoom = entryInfo.getCurrentRoom();
            if (currentRoom == null) {
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"现住房间为空!"});
            }
            //1.校验房间在原入住期间内有没有被其他人入住
            try {
                //根据单据id校验房间是否入住(批量)
                ValidateRoomAvailableByBillIdsUtil.startValidate(ctx, billId);
            } catch (Exception e) {
                logger.error(e);
                throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{e.getMessage()});
            }
            //没有水电明细的可以反审批
            occupants.setCheckOutDate(oldCheckoutDate);
            updateCols.add(occupants);
        }
        super._untiCheckBizBill(ctx, billId);
        if (updateCols.size() > 0) {
            //批量更新入住信息
            iOccupants.updateBatchData(updateCols);
        }
    }

    /**
     * 校验房间在原入住期间内有没有被其他人入住
     *
     * @param ctx
     * @param roomId
     * @param occupantsId
     * @param displayName
     * @param checkInDate
     * @param oldCheckoutDate
     * @throws BOSException
     * @throws BaseItemException
     */
    private void verifyOccupants(
            Context ctx,
            String roomId,
            String occupantsId,
            String displayName,
            Date checkInDate,
            Date oldCheckoutDate
    ) throws BOSException, BaseItemException {
        IOccupants iOccupants = OccupantsFactory.getLocalInstance(ctx);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        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", oldCheckoutDate, CompareType.LESS_EQUALS));
        filterItems.add(new FilterItemInfo("id", occupantsId, CompareType.NOTEQUALS));
        filterInfo.setMaskString("#0 and ((#1 and #2) or (#3 and #4)) and #5");
        SelectorItemCollection occupantsSic = new SelectorItemCollection();
        occupantsSic.add("person.name");
        EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, occupantsSic, null);
        OccupantsCollection occupantsCollection = iOccupants.getOccupantsCollection(viewInfo);
        for (int j = 0; j < occupantsCollection.size(); j++) {
            OccupantsInfo occupantsInfo = occupantsCollection.get(j);
            String personName = occupantsInfo.getPerson().getName();
            throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{
                    "入住信息中员工[" + personName + "]在" + sdf.format(checkInDate) + " ~ " + sdf.format(oldCheckoutDate) + "期间已入住房间[" + displayName + "]，无法反审批该退宿单"});

        }
    }
}