package thyyxxk.webserver.service.inpatient;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.sidicts.MedType;
import thyyxxk.webserver.dao.his.inpatient.ChargeListDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.inpatient.chargelist.BriefPatInfo;
import thyyxxk.webserver.entity.inpatient.chargelist.ChargeItem;
import thyyxxk.webserver.entity.inpatient.chargelist.PatOverview;
import thyyxxk.webserver.service.externalhttp.SiZySrvc;
import thyyxxk.webserver.service.hutoolcache.DeptCache;
import thyyxxk.webserver.service.hutoolcache.ZyBillItemCache;
import thyyxxk.webserver.utils.DateUtil;
import thyyxxk.webserver.utils.ResultVoUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

@Slf4j
@Service
public class ChargeListService {
    private final DeptCache deptCache;
    private final ZyBillItemCache billItemCache;
    private final ChargeListDao dao;
    private final SiZySrvc zySrvc;
    @Value("${si-zy-fee-url}")
    private String siZyFeeUrl;

    @Autowired
    public ChargeListService(DeptCache deptCache, ZyBillItemCache billItemCache, ChargeListDao dao, SiZySrvc zySrvc) {
        this.deptCache = deptCache;
        this.billItemCache = billItemCache;
        this.dao = dao;
        this.zySrvc = zySrvc;
    }

    public List<PatOverview> selectPatOverviews(String patNo) {
        return dao.selectPatOverviews(patNo);
    }

    public BriefPatInfo selectBriefPatInfo(PatOverview overview) {
        BriefPatInfo pat = dao.selectBriefPatInfo(
                overview.getPatNo(), overview.getTimes(), "zy_actpatient");
        if (null == pat) {
            pat = dao.selectBriefPatInfo(
                    overview.getPatNo(), overview.getTimes(), "zy_inactpatient");
        }
        if (null == pat) {
            return null;
        }
        pat.setMedtype(MedType.getName(pat.getMedtype()));
        pat.setDept(deptCache.get(pat.getDept()).getName());
        pat.setBegndate(overview.getBegndate());
        pat.setEnddate(overview.getEnddate());
        pat.setDays(Math.abs(calculateDaysBetween(pat.getBegndate(), pat.getEnddate())));
        return pat;
    }

    private int calculateDaysBetween(String date1Str, String date2Str) {
        LocalDate date1 = LocalDate.parse(date1Str);
        LocalDate date2 = LocalDate.parse(date2Str);
        long daysBetween = ChronoUnit.DAYS.between(date1, date2);
        return (int) (daysBetween + 1);
    }

    public Map<String, Object> selectChargeList(PatOverview v) {
        if (dao.isDischargedPatients(v) > 0) {
            dao.receiveCharges(v.getPatNo(), v.getTimes());
        }
        if (v.getFeeBelong() == 1) {
            v.setStatement(" and infant_flag=0");
        } else if (v.getFeeBelong() == 2) {
            v.setStatement(" and infant_flag=1");
        } else {
            v.setStatement("");
        }
        v.setBegndate(v.getBegndate() + " 00:00:00");
        v.setEnddate(v.getEnddate() + " 23:59:59.999");
        List<ChargeItem> chargeList = v.needChargeDate()
                ? dao.getChargeListWithChargeDate(v)
                : dao.getChargeListWithoutChargeDate(v);
        chargeList.removeIf(item -> BigDecimal.ZERO.compareTo(item.getQuantity()) == 0);
        for (ChargeItem item : chargeList) {
            item.setBillItemName(billItemCache.get(item.getBillItemCode()).getName());
        }
        Map<String, List<ChargeItem>> chargeListMap = new HashMap<>();
        Map<String, BigDecimal> sumsTempMap = new HashMap<>();
        sumsTempMap.put("总计", BigDecimal.ZERO);
        for (ChargeItem chargeItem : chargeList) {
            String mapKey = chargeItem.getBillItemName();
            sumsTempMap.replace("总计", sumsTempMap.get("总计").add(chargeItem.getCost()));
            if (chargeListMap.containsKey(mapKey)) {
                chargeListMap.get(mapKey).add(chargeItem);
                sumsTempMap.replace(mapKey, sumsTempMap.get(mapKey).add(chargeItem.getCost()));
            } else {
                List<ChargeItem> tempList = new ArrayList<>();
                tempList.add(chargeItem);
                chargeListMap.put(mapKey, tempList);
                sumsTempMap.put(mapKey, chargeItem.getCost());
            }
        }
        Map<String, String> sumsMap = new HashMap<>();
        for (Map.Entry<String, BigDecimal> entry : sumsTempMap.entrySet()) {
            sumsMap.put(entry.getKey(), entry.getValue().setScale(2, RoundingMode.HALF_DOWN).toString());
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("chargeList", chargeListMap);
        resultMap.put("sumsMap", sumsMap);
        return resultMap;
    }

    public ResultVo<String> executeSelfpayUpload(BriefPatInfo patInfo) {
        String patNo = patInfo.getPatNo();
        int times = patInfo.getTimes();
        int inhospCount = dao.selectInhospCount(patNo, times);
        if (inhospCount > 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者本次住院没有出院，不允许上传自费费用。");
        }
        List<Integer> siLedgers = dao.selectSiLedgers(patNo, times);
        List<Integer> allLedgers = dao.selectAllLedgers(patNo, times);
        allLedgers.removeIf(siLedgers::contains);
        if (allLedgers.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者本次住院不是自费住院，不允许上传自费费用。");
        }
        StringBuilder message = new StringBuilder();
        for (int ledgerSn : allLedgers) {
            patInfo.setLedgerSn(ledgerSn);
            JSONObject uploadResult = zySrvc.uploadSelfpayFees(siZyFeeUrl, patInfo);
            if (null != uploadResult && null != uploadResult.getInteger("code") && uploadResult.getInteger("code") == 0) {
                message.append("【账页").append(ledgerSn).append("】上传成功。");
            } else {
                message.append("【账页").append(ledgerSn).append("】上传失败。");
            }
        }
        return ResultVoUtil.success(message.toString());
    }

}
