package thyyxxk.webserver.controller.orderZdMaintain;

import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import thyyxxk.webserver.aop.interfaces.NeedMenu;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.orderZdMaintain.OrderZdMaintainDao;
import thyyxxk.webserver.dao.his.orderZdMaintain.YzOrderItemDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.dictionary.YzOrderOccurence;
import thyyxxk.webserver.entity.dictionary.ZdChargeClass;
import thyyxxk.webserver.entity.executeItem.ZdChargeItem;
import thyyxxk.webserver.entity.orderZdMaintain.dto.*;
import thyyxxk.webserver.entity.orderZdMaintain.dto.frequency.YzOrderFrequencyDTO;
import thyyxxk.webserver.entity.orderZdMaintain.enums.SupplyClass;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.YzZdOrderItemConfirm;
import thyyxxk.webserver.enums.authorize.MenuEnum;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.service.hutoolcache.CacheEnums;
import thyyxxk.webserver.service.hutoolcache.ExtraCache;
import thyyxxk.webserver.service.orderZdMaintain.OrderZdMaintainService;
import thyyxxk.webserver.utils.ListUtil;
import thyyxxk.webserver.utils.PingYinUtils;
import thyyxxk.webserver.utils.ResultVoUtil;
import thyyxxk.webserver.utils.StringUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/orderZdMaintain")
@RequiredArgsConstructor
public class OrderZdMaintainController {
    private final OrderZdMaintainService service;
    private final OrderZdMaintainDao dao;
    private final YzOrderItemDao yzOrderItemDao;
    private final ExtraCache extraCache;
    private final PublicServer publicServer;

    @GetMapping("/getChangeItemType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<CodeName>> getChangeItemType() {
        return ResultVoUtil.success(dao.getChangeItemType());
    }

    @GetMapping("/getSsType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<CodeName>> getSsType() {
        return ResultVoUtil.success(dao.getSsType());
    }

    @GetMapping("/getOrderItem")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<YzOrderItemDTO>> getOrderItem(@RequestParam("flag") String flag) {
        if ("0".equals(flag)) {
            return ResultVoUtil.success(dao.getOrderItem("isnull(del_flag, '0') <> '1'"));
        } else if ("1".equals(flag)) {
            return ResultVoUtil.success(dao.getOrderItem("isnull(del_flag, '0') = '1'"));
        } else if ("all".equals(flag)) {
            return ResultVoUtil.success(dao.getOrderItem("1=1"));
        }
        return ResultVoUtil.success(new ArrayList<>());
    }

    @GetMapping("/getChangeItem")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<OrderOccurrenceDTO>> getChangeItem(@RequestParam("orderCode") String orderCode) {
        return ResultVoUtil.success(dao.getChangeItem(orderCode));
    }

    @GetMapping("/searchChangeItem")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<ZdChargeItemDto>> searchChangeItem(@RequestParam("code") String code) {
        return ResultVoUtil.success(dao.searchChangeItem(code));
    }

    @PostMapping("/saveItem")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<YzOrderItemDTO> saveItem(@RequestBody YzOrderItemDTO params) {
        return service.saveItem(params);
    }

    @PostMapping("/setDelFlag")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> setDelFlag(@RequestBody YzOrderItemDTO params) {
        dao.stopChangeItem(params.getOrderCode(), params.getDelFlag());
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @PostMapping("/saveOrderOccurence")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> saveOrderOccurence(@RequestBody AddOrderOccurenceDTO params) {
        return service.saveOrderOccurence(params);
    }

    @GetMapping("/getAllYzOrderItemConfirm")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<YzZdOrderItemConfirm>> getAllYzOrderItemConfirm() {
        return ResultVoUtil.success(dao.getAllYzOrderItemConfirm());
    }

    @PostMapping("/saveOrderItemConfirm")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> saveOrderItemConfirm(@RequestBody YzZdOrderItemConfirm param) {
        try {
            int i = dao.insertOrderItemConfirm(param);
            if (i > 0) {
                extraCache.del(CacheEnums.YI_ZHU_SPECIAL_MEDICAL_ADVICE);
                return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
            }
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "插入失败");
        } catch (Exception e) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, e.getMessage());
        }
    }


    @PostMapping("/delOrderItemConfirm")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> delOrderItemConfirm(@RequestBody YzZdOrderItemConfirm param) {
        dao.deleteOrderItemConfirm(param);
        extraCache.del(CacheEnums.YI_ZHU_SPECIAL_MEDICAL_ADVICE);
        return ResultVoUtil.success();
    }

    @GetMapping("/selectOrderFrequency")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<YzOrderFrequencyDTO>> selectOrderFrequency() {
        return ResultVoUtil.success(dao.selectOrderFrequency());
    }

    @PostMapping("/saveOrderFrequency")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> saveOrderFrequency(@RequestBody YzOrderFrequencyDTO params) {
        return service.saveOrderFrequency(params);
    }

    @GetMapping("/deleteOrderFrequency")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> deleteOrderFrequency(@RequestParam("code") String code,
                                                 @RequestParam("delFlag") String delFlag) {
        dao.deleteOrderFrequency(code, delFlag);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @AllArgsConstructor
    @Data
    public static class TempCodeName {
        private Integer code;
        private String name;
    }

    @GetMapping("/getSupplyClass")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<TempCodeName>> getSupplyClass(@RequestParam("desc") String desc) {
        List<TempCodeName> codeNames = new ArrayList<>();
        for (SupplyClass value : SupplyClass.values()) {
            if (value.getDesc().equals("all") || value.getDesc().equals(desc)) {
                codeNames.add(new TempCodeName(value.getCode(), value.getName()));
            }
        }
        return ResultVoUtil.success(codeNames);
    }

    @GetMapping("/selectAllSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<YzSupplyTypeDTO>> selectAllSupplyType() {
        return ResultVoUtil.success(dao.selectAllSupplyType());
    }

    @GetMapping("/selectAllMzSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<MzZdSupplyType>> selectAllMzSupplyType() {
        return ResultVoUtil.success(dao.selectAllMzSupplyType());
    }

    @PostMapping("/insertSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> insertSupplyType(@RequestBody YzSupplyTypeDTO param) {
        param.setSupplyCode(publicServer.getSupplyNo());
        dao.insertSupplyType(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @PostMapping("/insertMzSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> insertMzSupplyType(@RequestBody MzZdSupplyType param) {
        param.setSupplyCode(publicServer.getMzSupplyNo());
        dao.insertMzSupplyType(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @PostMapping("/updateSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> updateSupplyType(@RequestBody YzSupplyTypeDTO param) {
        dao.updateSupplyType(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @PostMapping("/updateMzSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> updateMzSupplyType(@RequestBody MzZdSupplyType param) {
        dao.updateMzSupplyType(param);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @GetMapping("/deleteSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> deleteSupplyType(@RequestParam("code") String code,
                                             @RequestParam("delFlag") String delFlag) {
        dao.delSupplyType(code, delFlag);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @GetMapping("/deleteMzSupplyType")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> deleteMzSupplyType(@RequestParam("code") String code,
                                             @RequestParam("delFlag") String delFlag) {
        dao.delMzSupplyType(code, delFlag);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @Data
    public static class SupplyCharge {
        private String supplyCode;
        private String chargeCode;
        private String chargeName;
        private BigDecimal chargeAmount;
    }

    @GetMapping("/getSupplyCharge")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<SupplyCharge>> getSupplyCharge(@RequestParam("code") String code) {
        return ResultVoUtil.success(dao.getSupplyCharges(code));
    }

    @GetMapping("/getMzSupplyCharges")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<List<SupplyCharge>> getMzSupplyCharges(@RequestParam("code") String code) {
        return ResultVoUtil.success(dao.getMzSupplyCharges(code));
    }

    @GetMapping("/delSupplyCharge")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> delSupplyCharge(@RequestParam("code") String code,
                                            @RequestParam("chargeCode") String chargeCode) {
        dao.delSupplyCharge(code, chargeCode);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @GetMapping("/delMzSupplyCharge")
    @NeedMenu(MenuEnum.orderZdMaintain)
    public ResultVo<String> delMzSupplyCharge(@RequestParam("code") String code,
                                            @RequestParam("chargeCode") String chargeCode) {
        dao.delMzSupplyCharge(code, chargeCode);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @Data
    public static class SaveSupplyCharge {
        private String supplyCode;
        private List<SupplyCharge> list;
    }

    @PostMapping("/saveSupplyCharge")
    public ResultVo<String> saveSupplyCharge(@RequestBody SaveSupplyCharge param) {
        if (ListUtil.isBlank(param.getList())) {
            return ResultVoUtil.fail(ExceptionEnum.SUCCESS);
        }
        dao.delSupplyChargeByCode(param.getSupplyCode());
        ListUtil.batchList(param.getList(), OrderZdMaintainDao.class, (m, i) -> {
            if (StrUtil.isNotBlank(i.getChargeCode())) {
                m.insertSupplyCharge(param.getSupplyCode(), i.getChargeCode(), i.getChargeAmount());
            }
        });
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @PostMapping("/saveMzSupplyCharge")
    public ResultVo<String> saveMzSupplyCharge(@RequestBody SaveSupplyCharge param) {
        if (ListUtil.isBlank(param.getList())) {
            return ResultVoUtil.fail(ExceptionEnum.SUCCESS);
        }
        dao.delMzSupplyChargeByCode(param.getSupplyCode());
        ListUtil.batchList(param.getList(), OrderZdMaintainDao.class, (m, i) -> {
            if (StrUtil.isNotBlank(i.getChargeCode())) {
                m.insertMzSupplyCharge(param.getSupplyCode(), i.getChargeCode(), i.getChargeAmount());
            }
        });
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }

    @GetMapping("/getAllZdChargeClass")
    public ResultVo<List<ZdChargeClass>> getAllZdChargeClass() {
        return ResultVoUtil.success(dao.getAllZdChargeClass());
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/generateYzOrderItem")
    public ResultVo<String> generateYzOrderItem(@RequestBody List<String> yzClassCodeList) {
        List<ZdChargeClass> zdChargeClasses = dao.getZdChargeClassByYzClass(yzClassCodeList);
        for (ZdChargeClass zdChargeClass : zdChargeClasses) {
            List<ZdChargeItem> zdChargeItems = dao.getZdChargeItemByClassCode(zdChargeClass.getCode());
            if (ListUtil.isBlank(zdChargeItems)) {
                continue;
            }
            BigDecimal[] batchOrderNo = publicServer.getBatchOrderNo(zdChargeItems.size());
            BigDecimal minNo = batchOrderNo[0];
            BigDecimal maxNo = batchOrderNo[1];
            List<YzOrderItemDTO> yzOrderItemList = new ArrayList<>();
            List<YzOrderOccurence>  yzOrderOccurences = new ArrayList<>();
            for (ZdChargeItem zdChargeItem : zdChargeItems) {
                minNo = minNo.add(BigDecimal.ONE);
                YzOrderItemDTO yzOrderItem = new YzOrderItemDTO();
                yzOrderItem.setOrderCode(publicServer.fmtNoWithLead0(minNo, 5));
                yzOrderItem.setOrderName(StringUtil.trim(zdChargeItem.getName()));
                yzOrderItem.setPyCode(zdChargeItem.getPyCode());
                yzOrderItem.setDelFlag("0");
                yzOrderItem.setDiscription(zdChargeItem.getChargeAmount() + "元");
                yzOrderItem.setOrderClass(zdChargeClass.getYzClassCode());
                yzOrderItem.setExecDept(StringUtil.trim(zdChargeItem.getExecUnit()));
                yzOrderItemList.add(yzOrderItem);

                YzOrderOccurence yzOrderOccurence = new YzOrderOccurence();
                yzOrderOccurence.setOrderCode(yzOrderItem.getOrderCode());
                yzOrderOccurence.setOccCode(zdChargeItem.getCode());
                yzOrderOccurences.add(yzOrderOccurence);
            }
            if (minNo.compareTo(maxNo) != 0) {
                throw new BizException(ExceptionEnum.LOGICAL_ERROR, "生成医嘱出错！");
            }
            yzOrderItemDao.insert(yzOrderItemList, 100);
            insertYzOrderOccurenceBatch(yzOrderOccurences);
        }
        return ResultVoUtil.success("生成医嘱成功。");
    }

    private void insertYzOrderOccurenceBatch(List<YzOrderOccurence> list) {
        List<YzOrderOccurence> tempList = new ArrayList<>();
        for (YzOrderOccurence yzOrderOccurence : list) {
            tempList.add(yzOrderOccurence);
            if (tempList.size() == 100) {
                dao.insertYzOrderOccurenceBatch(tempList);
                tempList.clear();
            }
        }
        if (!tempList.isEmpty()) {
            dao.insertYzOrderOccurenceBatch(tempList);
        }
    }
}
