package thyyxxk.webserver.service.zygl;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import thyyxxk.webserver.constants.GenderEnum;
import thyyxxk.webserver.dao.his.dictionary.ZdUnitCodeDao;
import thyyxxk.webserver.dao.his.medicaladvice.common.DictDataDao;
import thyyxxk.webserver.dao.his.zygl.ZyActpatientDao;
import thyyxxk.webserver.dao.his.zygl.ZyDailySettlementDao;
import thyyxxk.webserver.entity.dictionary.ZdUnitCode;
import thyyxxk.webserver.entity.executeItem.NumberEnum;
import thyyxxk.webserver.entity.executeItem.ZyLedgerFile;
import thyyxxk.webserver.entity.inpatient.ZyActpatient;
import thyyxxk.webserver.entity.inpatient.charge.PatientParam;
import thyyxxk.webserver.entity.zygl.CodeNameEntity;
import thyyxxk.webserver.entity.zygl.ZyDailySettlementVo;
import thyyxxk.webserver.entity.zygl.ZyDayclosingRecord;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.service.inpatient.charge.CashierProcessService;
import thyyxxk.webserver.utils.AssertUtil;
import thyyxxk.webserver.utils.TokenUtil;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ZyDailySettlementService  {
    @Resource
    private ZyDailySettlementDao zyDailySettlementMapper;
    @Resource
    private ZyActpatientDao zyActpatientDao;
    @Resource
    private UserCache userCache;
    @Resource
    private ZdUnitCodeDao zdUnitCodeDao;
    @Resource
    private DictDataDao dictDataDao;
    @Resource
    private CashierProcessService cashierProcessService;
    /**
     * @description: 住院日结操作
     * @author: lihong
     * @date: 2025/5/13 17:44
     * @param: parse
     * @param: tokenUserId
     **/
    @Transactional(rollbackFor = Exception.class)
    public void dayClosing(Date dateEnd, String opId) {
        AssertUtil.isnotBlank(dateEnd,"结束时间不能为空");
        AssertUtil.isnotBlank(opId,"用户编码不能为空");
        Date lastCloseDate = zyDailySettlementMapper.selectLastCloseDate(opId);
        if(lastCloseDate==null){
            lastCloseDate=DateUtil.parseDateTime("2021-06-04 00:00:00");
        }
        Date closeDate = new Date();
        zyDailySettlementMapper.insertZyDayclosingRecord(closeDate, lastCloseDate,dateEnd,opId);
        zyDailySettlementMapper.updateZyLedgerFile(closeDate, lastCloseDate,dateEnd,opId);

    }

    public ZyDailySettlementVo getZyDailySettlementVo(ZyDayclosingRecord param)  {
        Date now;
        Date lastDailyDate;
        String opId;
        if(NumberEnum.ONE.getCode().equals(param.getType())){
             opId = TokenUtil.getInstance().getTokenUserId();
             now = new Date();
             lastDailyDate = zyDailySettlementMapper.getLastDailyDateForUser(opId);
            if(lastDailyDate==null){
                lastDailyDate= DateUtil.parseDateTime("2021-06-04 00:00:00");
            }
        }else {
             opId = param.getOpId();
            AssertUtil.isnotBlank(opId,"用户编码不能为空");
            lastDailyDate = param.getDateStart();
            now = param.getDateEnd();
        }
        ZyDailySettlementVo zyDailySettlementVo = new ZyDailySettlementVo();
        zyDailySettlementVo.setOpName(userCache.getEmployeeName(opId));
        zyDailySettlementVo.setOpCodeRs(userCache.get(opId).getCodeRs());
        zyDailySettlementVo.setLastDailyDate(DateUtil.format(lastDailyDate, "yyyy-MM-dd HH:mm:ss"));
        zyDailySettlementVo.setCurrentDate(DateUtil.format(now, "yyyy-MM-dd HH:mm:ss"));
        dealDzfp(opId, lastDailyDate, now);
        Map<String, Object> map = zyDailySettlementMapper.selectTotalChargeFromLegerFile(opId, lastDailyDate, now);
        setAttribute(zyDailySettlementVo, map);
        map = zyDailySettlementMapper.selectYjjFromDepositFile(opId, lastDailyDate, now);
        setAttribute(zyDailySettlementVo, map);
        map = zyDailySettlementMapper.selectHsJeAndHsCount(opId, lastDailyDate, now);
        setAttribute(zyDailySettlementVo, map);
        //设置预交金合计
        zyDailySettlementVo.sumtDepositTotal();
        List<CodeNameEntity> zdChequeTypeList = zyActpatientDao.selectZdChequeType();
        Map<String, String> chequeTypeMap = zdChequeTypeList.stream().collect(Collectors.toMap(CodeNameEntity::getCode, CodeNameEntity::getName));
        Map<String, String> employeeMap = new HashMap<>();
        List<Map<String, Object>> refunfZyDepositFileList = zyDailySettlementMapper.selectRefunfZyDepositFile(opId, lastDailyDate, now);
        setChargeZyDepositFileList(opId, zyDailySettlementVo, now, lastDailyDate, chequeTypeMap,employeeMap,refunfZyDepositFileList);
        setRefunfZyDepositFileList(opId, zyDailySettlementVo, now, lastDailyDate, chequeTypeMap,refunfZyDepositFileList);
        setZyChargeDetailList(opId, zyDailySettlementVo, now, lastDailyDate);
        setJsYjjDetailList(opId, zyDailySettlementVo, now, lastDailyDate,employeeMap);
        setJsfydjbb(opId, zyDailySettlementVo, now, lastDailyDate);
        return zyDailySettlementVo;
    }

    private void dealDzfp(String opId, Date lastDailyDate, Date now) {
        List<ZyLedgerFile> zyLedgerFiles = zyDailySettlementMapper.selectCashPatientByOpId(opId, lastDailyDate, now);
        for(ZyLedgerFile zyLedgerFile : zyLedgerFiles){
            try {
                PatientParam param = new PatientParam();
                param.setInpatientNo(zyLedgerFile.getInpatientNo());
                param.setAdmissTimes(zyLedgerFile.getAdmissTimes());
                param.setLedgerSn(zyLedgerFile.getLedgerSn());
                param.setReceiptSn(1);
                param.setTypeFlag(3);
                param.setType("0");
                String dzfp = zyDailySettlementMapper.selectzyReceiptDzfp(zyLedgerFile);
                if(StrUtil.isBlank(dzfp)){
                    cashierProcessService.downDzInvoice(param);
                    Integer babyCount = zyDailySettlementMapper.selectCountZyReceiptDzfpBaby(zyLedgerFile);
                    if(babyCount > 0){
                        param.setReceiptSn(4);
                        cashierProcessService.downDzInvoice(param);
                    }
                }
            }catch (Exception e){
                log.error("住院日结报表同步电子发票报错",e);
            }
        }
    }

    /**
     * 结算费用登记报表
     *
     * @param opId
     * @param zyDailySettlementVo
     * @param now
     * @param lastDailyDate
     */
    private void setJsfydjbb(String opId, ZyDailySettlementVo zyDailySettlementVo, Date now, Date lastDailyDate) {
        List<Map<String, Object>> jsfydjbb = zyDailySettlementMapper.selectJsFydjbb(ZyActpatient.ZY_ACTPATIENT, opId, lastDailyDate, now);
        List<Map<String, Object>> jsfydjbbInt = zyDailySettlementMapper.selectJsFydjbb(ZyActpatient.ZY_INACTPATIENT, opId, lastDailyDate, now);
        if (jsfydjbb == null) {
            jsfydjbb = jsfydjbbInt;
        } else {
            jsfydjbb.addAll(jsfydjbbInt);
        }
        if (jsfydjbb != null && jsfydjbb.size() > 0) {
            jsfydjbb.stream().forEach(j -> {
                String sexStr = (String) j.get("sex");
                if (StringUtils.isNotBlank(sexStr)) {
                    GenderEnum gender = GenderEnum.getGenderByCode(Integer.valueOf(sexStr));
                    j.put("gender", gender == null ? "" : gender.name);
                }

                j.put("responce_type_name", zyActpatientDao.selectResponceTypeName(Convert.toStr(j.get("responce_type"))));
                ZdUnitCode zdUnitCode = zdUnitCodeDao.selectDeptDictByCode((String) j.get("ward"));
                j.put("ward_name", zdUnitCode == null ? "" : zdUnitCode.getName());
            });
        }
        zyDailySettlementVo.setJsfydjbb(jsfydjbb);
    }

    /**
     * 预交金收费列表
     *
     * @param opId
     * @param zyDailySettlementVo
     * @param now
     * @param lastDailyDate
     * @param chequeTypeMap
     */
    private void setChargeZyDepositFileList(String opId, ZyDailySettlementVo zyDailySettlementVo, Date now, Date lastDailyDate, Map<String, String> chequeTypeMap,Map<String, String> employeeMap,List<Map<String, Object>> refunfZyDepositFileList) {
        List<Map<String, Object>> chargeZyDepositFileList = zyDailySettlementMapper.selectChargeZyDepositFile(opId, lastDailyDate, now);
        if (chargeZyDepositFileList == null) {
            chargeZyDepositFileList = refunfZyDepositFileList;
        } else {
            chargeZyDepositFileList.addAll(refunfZyDepositFileList);
        }
        if (chargeZyDepositFileList != null && chargeZyDepositFileList.size() > 0) {
            chargeZyDepositFileList.stream().forEach(r -> {
                r.put("depo_type_name", chequeTypeMap.get(r.get("depo_type")));
                setOpName(employeeMap, r);
                ZdUnitCode zdUnitCode = zdUnitCodeDao.selectDeptDictByCode((String) r.get("ward"));
                r.put("ward_name", zdUnitCode == null ? "" : zdUnitCode.getName());
            });
            Collections.sort(chargeZyDepositFileList, (o1, o2) -> {
                String receipt_no1 =(String)o1.get("receipt_no");
                String receipt_no2= (String)o2.get("receipt_no");
                if(receipt_no1==null){
                    receipt_no1="";
                }
                if(receipt_no2==null){
                    receipt_no2="";
                }
                return receipt_no1.compareTo(receipt_no2);
            });
            zyDailySettlementVo.setReceiptNoBegin((String) chargeZyDepositFileList.get(0).get("receipt_no"));
            zyDailySettlementVo.setReceiptNoEnd((String) chargeZyDepositFileList.get(chargeZyDepositFileList.size() - 1).get("receipt_no"));
        }
        zyDailySettlementVo.setChargeZyDepositFileList(chargeZyDepositFileList);
    }

    /**
     * 预交金退费列表
     *
     * @param opId
     * @param zyDailySettlementVo
     * @param now
     * @param lastDailyDate
     * @param chequeTypeMap
     */
    private void setRefunfZyDepositFileList(String opId, ZyDailySettlementVo zyDailySettlementVo, Date now, Date lastDailyDate, Map<String, String> chequeTypeMap,List<Map<String, Object>> refunfZyDepositFileList) {
        List<Map<String, Object>> deleteZyChargeDetailList = zyDailySettlementMapper.selectDeleteZyChargeDetail(opId, lastDailyDate, now);
        if (deleteZyChargeDetailList == null) {
            deleteZyChargeDetailList = refunfZyDepositFileList;
        } else {
            deleteZyChargeDetailList.addAll(refunfZyDepositFileList);
        }
        if (deleteZyChargeDetailList != null && deleteZyChargeDetailList.size() > 0) {
            deleteZyChargeDetailList.stream().forEach(r -> {
                r.put("depo_type_name", chequeTypeMap.get(r.get("depo_type")));
            });
        }
        zyDailySettlementVo.setRefunfZyDepositFileList(deleteZyChargeDetailList);
    }

    /**
     * 结算病人明细
     *
     * @param opId
     * @param zyDailySettlementVo
     * @param now
     * @param lastDailyDate
     */
    private void setZyChargeDetailList(String opId, ZyDailySettlementVo zyDailySettlementVo, Date now, Date lastDailyDate) {
        List<Map<String, Object>> zyChargeDetailList = zyDailySettlementMapper.selectZyChargeDetail(opId, lastDailyDate, now);
        if (zyChargeDetailList != null && zyChargeDetailList.size() > 0) {
            zyDailySettlementVo.setJsReceiptNoBegin((String) zyChargeDetailList.get(0).get("receipt_no"));
            zyDailySettlementVo.setJsReceiptNoEnd((String) zyChargeDetailList.get(zyChargeDetailList.size() - 1).get("receipt_no"));
        }
        zyDailySettlementVo.setZyChargeDetailList(zyChargeDetailList);
    }

    /**
     * 结算预交金明细
     *
     * @param opId
     * @param zyDailySettlementVo
     * @param now
     * @param lastDailyDate
     */
    private void setJsYjjDetailList(String opId, ZyDailySettlementVo zyDailySettlementVo, Date now, Date lastDailyDate,Map<String, String> employeeMap) {
        List<Map<String, Object>> jsYjjDetailList = zyDailySettlementMapper.selectJsYjjDetail(opId, lastDailyDate, now);
        if (jsYjjDetailList != null && jsYjjDetailList.size() > 0) {
            jsYjjDetailList.stream().forEach(r -> {
                setOpName(employeeMap, r);
            });
        }
        zyDailySettlementVo.setJsYjjDetailList(jsYjjDetailList);
    }

    /**
     * 设置操作员名称
     * @param employeeMap
     * @param r
     */
    private void setOpName(Map<String, String> employeeMap, Map<String, Object> r) {
        String opIdCode = (String) r.get("op_id_code");
        String name = employeeMap.get(opIdCode);
        if (StringUtils.isBlank(name)) {
            employeeMap.put(opIdCode, userCache.getEmployeeName(opIdCode));
            name = userCache.getEmployeeName(opIdCode);
        }
        r.put("op_id_name", name);
    }

    /**
     * 通过反射的方式设置属性值
     *
     * @param zyDailySettlementVo
     * @param map
     */
    private void setAttribute(ZyDailySettlementVo zyDailySettlementVo, Map<String, Object> map) {
        if (map != null && map.size() > 0) {
            for (String key : map.keySet()) {
                try {
                    Field field = zyDailySettlementVo.getClass().getDeclaredField(key);
                    field.setAccessible(true);
                    field.set(zyDailySettlementVo, map.get(key));
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("属性 【{}】设置失败，错误信息{}", key, e.getMessage());
                }
            }
        }
    }
    /**
     * @description: 查询医院名称
     * @author: lihong
     * @date: 2025/5/14 9:30
     * @return: java.lang.String
     **/
    public String queryHospitalName() {
        String hospitalName = dictDataDao.getDictValueByDictName("4.2", "hospital_name");
        if(StrUtil.isBlank(hospitalName)){
            hospitalName = "沭阳铭和医院";
        }
        return hospitalName;
    }
    /**
     * @description: 查询住院日结记录
     * @author: lihong
     * @date: 2025/6/12 9:15
     * @param: param
     * @return: java.util.List<thyyxxk.webserver.entity.zygl.ZyDayclosingRecord>
     **/
    public List<ZyDayclosingRecord> queryZyDayclosingRecord(ZyDayclosingRecord param) {
        List<String> roleNames = zyDailySettlementMapper.selectRoleNamesByUserCode(TokenUtil.getInstance().getTokenUserId());
        if(userCache.get(TokenUtil.getInstance().getTokenUserId()).getRoles().contains(1) || roleNames.contains("住院日结组长")){
            param.setOpId(null);
        }else {
            param.setOpId(TokenUtil.getInstance().getTokenUserId());
        }
        return zyDailySettlementMapper.selectZyDayclosingRecord(param);
    }
}
