package thyyxxk.webserver.service.medicine;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.medicine.YpPlanDetailDao;
import thyyxxk.webserver.dao.his.medicine.YpPlanInfoDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.entity.medicine.YpPlanDetail;
import thyyxxk.webserver.entity.medicine.YpPlanInfo;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.utils.DecimalUtil;
import thyyxxk.webserver.utils.ResultVoUtil;
import thyyxxk.webserver.utils.StringUtil;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName YpPlanService
 * @Author hsh
 * @Date 2025/2/20 9:21
 * @Version 1.0
 * @Description 药品计划申请与审核
 **/
@Service
@Slf4j
public class YpPlanService {

    private final YpPlanInfoDao infoDao;
    private final YpPlanDetailDao detailDao;
    private final UserCache userCache;

    public YpPlanService(YpPlanInfoDao infoDao, YpPlanDetailDao detailDao, UserCache userCache) {
        this.infoDao = infoDao;
        this.detailDao = detailDao;
        this.userCache = userCache;
    }

    /**
     * @Description 查询药品申请与审核信息
     * @Author hsh
     * @param info 药品申请与审核信息
     * @return list
     * @Date 2025/2/21 9:54
     */
    public ResultVo<List<YpPlanInfo>> selectYpPlanInfo(YpPlanInfo info){
        List<YpPlanInfo> list = infoDao.selectYpPlanInfo(info);
        return ResultVoUtil.success(list);
    }

    /**
     * @Description 查询药品申请与审核信息导入明细
     * @Author hsh
     * @param detail 药品申请与审核信息导入明细
     * @return list
     * @Date 2025/2/21 9:55
     */
    public ResultVo<List<YpPlanDetail>> selectYpPlanDetail(YpPlanDetail detail){
        QueryWrapper<YpPlanDetail> querywrapper = new QueryWrapper<>();
        querywrapper.eq("file_id", detail.getFileId());
        querywrapper.like("supply_name", detail.getSupplyName());
        List<YpPlanDetail> list = detailDao.selectList(querywrapper);
        return ResultVoUtil.success(list);
    }

    public ResultVo<List<YpPlanDetail>> selectYpPlanDetailById(YpPlanDetail detail){
        List<YpPlanDetail> list = detailDao.selectYpPlanDetailById(detail.getFileId());
        return ResultVoUtil.success(list);
    }

    /**
     * @Description 保存药品申请与审核信息导入明细
     * @Author hsh
     * @param info 药品申请与审核信息导入明细
     * @return map
     * @Date 2025/2/21 9:57
     */
    public ResultVo<Map<String, Object>> saveYpPlanFile(YpPlanInfo info) {
        Map<String, Object> map = new HashMap<>();
        String fileId = info.getFileId();
        String fileName = info.getFileName();
        LocalDate now = LocalDate.now();
        int year = now.getYear();
        int month = now.getMonthValue();
        String ny = year + "" + (month < 10 ? "0" + month : month);
        MultipartFile file = info.getFile();
        try {
            // 解析导入的数据
            List<YpPlanDetail> list = new ArrayList<>();
            String str = callYpPlanImportData(list, fileId, file, ny);
            if(!"0".equals(str)){
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, str);
            }
            if(list.isEmpty()){
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "导入药品申请与审核药品明细为空，请确认！");
            }
            // 计算购入总金额
            BigDecimal totalFee = BigDecimal.ZERO;
            for(YpPlanDetail d : list){
                totalFee = DecimalUtil.add(totalFee, d.getBuyMoney());
                // 计算当月累计已审批计划量
                int plan = detailDao.selectYpPlanTotalByMonth(d.getChargeCode(), ny);
                d.setPlanTotal(Convert.toStr(plan, "0"));
                // 计算当月累计实际入库量
                int real = detailDao.selectYpRealTotalByMonth(d.getChargeCode(), ny);
                d.setRealTotal(Convert.toStr(real, "0"));
            }
            info.setTotalFee(totalFee);
            UserInfo user = userCache.getUserInfoByToken();
            info.setApplyId(user.getCode());
            info.setApplyName(user.getName());
            int c = callSavePlanDetail(info, list);
            if(c > 0){
                map.put("msg", "导入药品计划成功!");
            } else {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "导入药品计划明细存储出错！");
            }
        } catch (IOException e) {
            log.info("导入药品计划出错：" + e.getMessage());
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "导入药品计划出错：" + e.getMessage());
        }
        return ResultVoUtil.success(map);
    }

    private static final int BATCH_SIZE = 60;

    /**
     * @Description 药品计划导入数据excel解析
     * @Author hsh
     * @param impList 导入接收数据
     * @param fileId 文件id
     * @param file 文件
     * @param ny 年月
     * @return list
     * @Date 2025/2/21 16:19
     */
    private String callYpPlanImportData(List<YpPlanDetail> impList, String fileId, MultipartFile file, String ny) throws IOException {
        Workbook workbook;
        StringBuilder str = new StringBuilder();
        try (InputStream is = file.getInputStream()) {
            workbook = WorkbookFactory.create(is);
            // 获取第一个活页数据
            Sheet sheet = workbook.getSheetAt(0);
            // 第几行开始解析
            int rowStart = 2;
            for (int i = rowStart; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                // 第二个药品名称必填
                if (null == row.getCell(1) || StringUtil.isBlank(row.getCell(1).getStringCellValue())) {
                    continue;
                }
                // 获取行所有单元格数据
                int colNum = row.getPhysicalNumberOfCells();
                int j = 0;
                while (j < colNum) {
                    str.append(getCellStringVal(row.getCell(j)).trim()).append("_");
                    j++;
                }
                YpPlanDetail imp = new YpPlanDetail();
                String[] stirs = str.toString().split("_");
                imp.setRemark(stirs[0]);
                imp.setSupplyName(stirs[1]);
                imp.setChargeCode(stirs[2]);
                imp.setDrugName(stirs[3]);
                imp.setSpecification(stirs[4]);
                imp.setDrugKind(stirs[5]);
                imp.setIsWinning(stirs[6]);
                if (StringUtil.notBlank(stirs[7])) {
                    imp.setPackRetprice(new BigDecimal(stirs[7]));
                    imp.setPackRetprice1(stirs[7]);
                }
                if (StringUtil.notBlank(stirs[8])) {
                    imp.setBuyPrice(new BigDecimal(stirs[8]));
                    imp.setBuyPrice1(stirs[8]);
                }
                if (StringUtil.notBlank(stirs[9])) {
                    imp.setAmount(new BigDecimal(stirs[9]));
                }
                imp.setManuName(stirs[10]);
                if (StringUtil.notBlank(stirs[11])) {
                    imp.setAmount3(new BigDecimal(stirs[11]));
                }
                if (StringUtil.notBlank(stirs[12])) {
                    imp.setAmount7(new BigDecimal(stirs[12]));
                }
                if (StringUtil.notBlank(stirs[13])) {
                    imp.setAmount14(new BigDecimal(stirs[13]));
                }
                if (StringUtil.notBlank(stirs[14])) {
                    imp.setAmount30(new BigDecimal(stirs[14]));
                }
                if (StringUtil.notBlank(stirs[15])) {
                    imp.setAmount60(new BigDecimal(stirs[15]));
                }
                imp.setDays(stirs[16]);
                if (StringUtil.notBlank(stirs[17])) {
                    imp.setBuyAmount(new BigDecimal(stirs[17]));
                }
                // 单位
                if (stirs.length >= 19 && StringUtil.notBlank(stirs[18])) {
                    imp.setUnit(stirs[18]);
                }
                // 购入价金额
                if (null == imp.getBuyPrice() || null == imp.getBuyAmount()) {
                    imp.setBuyFee(BigDecimal.ZERO);
                    imp.setBuyMoney(BigDecimal.ZERO);
                } else {
                    imp.setBuyFee(DecimalUtil.multiply(imp.getBuyPrice(), imp.getBuyAmount()));
                    imp.setBuyMoney(DecimalUtil.multiply(imp.getBuyPrice(), imp.getBuyAmount()));
                }
                // 主任意见
                if (stirs.length == 21 && StringUtil.notBlank(stirs[20])) {
                    imp.setContent(stirs[20]);
                }
                imp.setFileId(fileId);
                // 常量
                LocalDateTime now = LocalDateTime.now();
                DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                imp.setImpDate(now.format(sdf));
                imp.setMonth(ny);
                impList.add(imp);
                str = new StringBuilder();
            }
            workbook.close();
        } catch (Exception e) {
            log.info("药品计划导入解析excel出错：" + e.getMessage());
            return "药品计划导入解析excel出错！";
        }

        return "0";
    }

    private int callSavePlanDetail(YpPlanInfo info, List<YpPlanDetail> list) {
        YpPlanInfo info1 = infoDao.selectYpPlanInfoById(info.getFileId());
        if (null != info1) {
            infoDao.deleteYpPlanInfoById(info.getFileId());
        }
        infoDao.insert(info);
        List<YpPlanDetail> listLs = detailDao.selectYpPlanDetailById(info.getFileId());
        if (null != listLs && !listLs.isEmpty()) {
            detailDao.deleteYpPlanDetailById(info.getFileId());
        }
        return countNum(list);
    }

    private String getCellStringVal(Cell cell) {
        String cellType = cell.getCellType().name();
        switch (cellType) {
            case "NUMERIC":
                short format = cell.getCellStyle().getDataFormat();
                if (DateUtil.isCellDateFormatted(cell)) {
                    SimpleDateFormat sdf;
                    if (format == 20 || format == 32) {
                        sdf = new SimpleDateFormat("HH:mm");
                    } else if (format == 14 || format == 31 || format == 57 || format == 58) {
                        // 处理自定义日期格式：m月d日(通过判断单元格的格式id解决，id的值是58)
                        sdf = new SimpleDateFormat("yyyy-MM-dd");
                        double value = cell.getNumericCellValue();
                        Date date = DateUtil.getJavaDate(value);
                        return sdf.format(date);
                    } else {
                        // 日期
                        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    return sdf.format(cell.getDateCellValue());
                }  else {
                    BigDecimal bd = BigDecimal.valueOf(cell.getNumericCellValue());
                    // 数值 用BigDecimal包装再获取plainString，可以防止获取到科学计数值
                    return bd.toPlainString();
                }
            case "STRING":
                return cell.getRichStringCellValue().getString();
            case "BOOLEAN":
                return String.valueOf(cell.getBooleanCellValue());
            case "FORMULA":
                return cell.getCellFormula();
            case "ERROR":
                return String.valueOf(cell.getErrorCellValue());
            default:
                return "";
        }
    }

    private String formatString(Object... paras) {
        return MessageFormat.format("{0}|{1}|{2}", paras);
    }

    /**
     * @Description 更新药品计划审核状态
     * @Author hsh
     * @param info 信息
     * @return map
     * @Date 2025/2/26 14:33
     */
    public ResultVo<Map<String, Object>> updateYpPlanAuditData(YpPlanInfo info){
        Map<String, Object> map = new HashMap<>();
        int type = info.getType();
        String fileId = info.getFileId();
        if(StringUtil.isBlank(fileId)){
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到药品计划审核id，审核失败！");
        }
        if(!(type == 1 || type == 2 || type == 3)){
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "不是药品计划审核状态，审核失败！");
        }
        UserInfo user = userCache.getUserInfoByToken();
        if(type == 1){
            info.setTrialContent(info.getContent());
            info.setTrialId(user.getCode());
            info.setTrialName(user.getName());
        } else if(type == 2){
            info.setReviewContent(info.getContent());
            info.setReviewId(user.getCode());
            info.setReviewName(user.getName());
        } else {
            info.setFinalContent(info.getContent());
            info.setFinalId(user.getCode());
            info.setFinalName(user.getName());
        }
        int d = infoDao.updateYpPlanAuditById(info);
        if(d > 0){
            map.put("cg", "药品计划意见审核成功！");
            return ResultVoUtil.success(map);
        } else {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "药品计划意见审核失败！");
        }
    }

    /**
     * @Description 药品计划审核时确认计划数量以及金额
     * @Author hsh
     * @param list 药品计划数量以及金额
     * @return map
     * @Date 2025/3/27 10:45
     */
    public ResultVo<Map<String, Object>> saveYpPlanDetail(List<YpPlanDetail> list){
        Map<String, Object> map = new HashMap<>();
        if(null == list || list.isEmpty()){
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "药品计划明细不存在，药品计划审核失败！");
        }
        List<YpPlanDetail> listLs = detailDao.selectYpPlanDetailById(list.get(0).getFileId());
        if (null != listLs && !listLs.isEmpty()) {
            detailDao.deleteYpPlanDetailById(list.get(0).getFileId());
        }
        int c = countNum(list);
        if(c > 0){
            map.put("cg", "药品计划审核成功！");
            return ResultVoUtil.success(map);
        } else {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "药品计划审核失败！");
        }
    }

    private int countNum(List<YpPlanDetail> list) {
        int c = 0;
        int cs = (int) Math.ceil((double) list.size() / BATCH_SIZE);
        for(int i = 0; i < cs; i++ ){
            int start = i * BATCH_SIZE;
            int end = Math.min(start + BATCH_SIZE, list.size());
            List<YpPlanDetail> l = list.subList(start, end);
            c = c + detailDao.insertList(l);
        }
        return c;
    }
}
