package cn.iocoder.yudao.module.system.service.biz;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.DailyExpensesExcelVO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.*;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
import cn.iocoder.yudao.module.system.enums.change.BusinessConstants;
import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.EXPENSE_ORDER_IS_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;


/**
 * 日常费用 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class DailyExpensesServiceImpl implements DailyExpensesService {


    @Resource
    private BuildService buildService;

    @Resource
    private DailyExpensesMapper dailyExpensesMapper;

    @Resource
    private ElderlyInfoMapper elderlyInfoMapper;

    @Resource
    private SysOverheadChargeMapper sysOverheadChargeMapper;

    @Resource
    private SysChargeCategoryMapper sysChargeCategoryMapper;

    @Resource
    private ExpenseOrderMapper expenseOrderMapper;

    @Resource
    private ExpenseOrderItemMapper expenseOrderItemMapper;

    @Resource
    private TenantMapper tenantMapper;
    @Resource
    private RefundSettlementOrderMapper refundSettlementOrderMapper;
    @Resource
    private RefundSettlementOrderItemMapper refundSettlementOrderItemMapper;
    @Resource
    private MedicineInventoryService medicineInventoryService;
    @Resource
    private MedicineInOutRecordsService medicineInOutRecordsService;


    @Override
    @LogRecord(type = ELDERLY_DAILY_EXPENSES_TYPE, subType = ELDERLY_DAILY_EXPENSES_CREATE_SUB_TYPE, bizNo = "{{#elder.id}}",
            success = ELDERLY_DAILY_EXPENSES_CREATE_SUCCESS, extra = "{{#elder.id}}")
    public void createDailyExpenses(DailyExpensesSaveReqVO createReqVO) {
        Long elderId = createReqVO.getElderId();
        ElderlyInfoDO elder = elderlyInfoMapper.selectById(elderId);
        List<DailyExpensesDO> dailyExpensesList = createReqVO.getDailyExpenses();
        // 是否零星账单
        boolean isSingleOrder = BooleanEnum.TRUE.getValue().equals(createReqVO.getIsCashSettlementFee());
        // 是否是现结费用，生成零星账单
        ExpenseOrderDO expenseOrder = null;
        if (isSingleOrder) {
            expenseOrder = new ExpenseOrderDO();
            expenseOrder.setBillingMonth(createReqVO.getAttributionBillTime());
            expenseOrder.setCreatedTime(new Date());
            expenseOrder.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            expenseOrder.setElderId(elderId);
            expenseOrder.setBillOrderNumber("E" + RandomUtil.randomNumbers(16));
            expenseOrder.setType(4); // 零星账单
            expenseOrder.setActualAmount(BigDecimal.ZERO);
            expenseOrder.setOrgType(elder.getOrgType());
            expenseOrder.setTenantId(elder.getTenantId());
            expenseOrderMapper.insert(expenseOrder);
        }

        BigDecimal updatedAmount = BigDecimal.ZERO;
        for (DailyExpensesDO dailyExpenses : dailyExpensesList) {
            // 如果不是零星账单则查询是否存在归属月账单，存在则自动带入费用
            if(!isSingleOrder){
                List<ExpenseOrderDO> expenseOrderDOS = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                        .ne(ExpenseOrderDO::getPayStatus, 1)
                        .eq(ExpenseOrderDO::getIsLock,Boolean.FALSE)
                        .eq(ExpenseOrderDO::getElderId, elderId)
                        .eq(ExpenseOrderDO::getBillingMonth,createReqVO.getAttributionBillTime())
                        .in(ExpenseOrderDO::getType, 1, 2));
                if(CollectionUtil.isNotEmpty(expenseOrderDOS)){
                    expenseOrder = expenseOrderDOS.get(0);
                }
            }
            if(expenseOrder != null){
                dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
            }
            dailyExpenses.setType(isSingleOrder ? 4 : 1);  //1.入院账单 4.零星账单
            dailyExpenses.setElderId(elderId);
            dailyExpenses.setAttributionBillTime(createReqVO.getAttributionBillTime());
            dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));  // 四舍五入取整
            dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
            dailyExpenses.setTenantId(elder.getTenantId());
            dailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            dailyExpensesMapper.insert(dailyExpenses);
            if (expenseOrder != null) {
                // 生成订单细项
                ExpenseOrderItemDO expenseOrderItem = createExpenseOrderItem(expenseOrder.getId(), dailyExpenses);
                expenseOrderItemMapper.insert(expenseOrderItem);

                // 更新账单金额
                updatedAmount = updatedAmount.add(expenseOrderItem.getTotalAmount());
            }
            updateRefundOrder(dailyExpenses,false,false);
        }
        if (expenseOrder != null) {
            expenseOrder.setActualAmount(expenseOrder.getActualAmount().add(updatedAmount));
            expenseOrderMapper.updateById(expenseOrder);
        }

        LogRecordContext.putVariable("elder", elder);
    }

    @Override
    public DailyExpensesRespVO getDailyExpenses(Long id) {
        DailyExpensesRespVO respVO = new DailyExpensesRespVO();
        DailyExpensesDO dailyExpensesDO = dailyExpensesMapper.selectById(id);
        if (dailyExpensesDO != null) {
            ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(dailyExpensesDO.getElderId());
            respVO.setElderId(elderlyInfoDO.getId());
            respVO.setDailyExpenses(dailyExpensesDO);
            respVO.setElderName(elderlyInfoDO.getElderName());
            respVO.setBedName(buildService.getFullBedName(elderlyInfoDO.getId()));
            respVO.setAttributionBillTime(dailyExpensesDO.getAttributionBillTime());
            respVO.setIdCard(StringUtils.isBlank(elderlyInfoDO.getIdCard()) ? null : elderlyInfoDO.getIdCard());
            respVO.setNurseLevelName(StringUtils.isBlank(elderlyInfoDO.getNurseLevelName()) ? null : elderlyInfoDO.getNurseLevelName());
            respVO.setSocialSecurityCardNumber(StringUtils.isBlank(elderlyInfoDO.getSocialSecurityCardNumber()) ? null : elderlyInfoDO.getSocialSecurityCardNumber());
        }
        return respVO;
    }

    @Override
    @LogRecord(type = ELDERLY_DAILY_EXPENSES_TYPE, subType = ELDERLY_DAILY_EXPENSES_DELETE_SUB_TYPE, bizNo = "{{#dailyExpenses.id}}",
            success = ELDERLY_DAILY_EXPENSES_DELETE_SUCCESS, extra = "{{#dailyExpenses.elderId}}")
    public void deleteDailyExpenses(Long id) {
        DailyExpensesDO dailyExpensesDO = dailyExpensesMapper.selectById(id);
        // 该日常费用是否已完成缴费
        boolean isPay = false;
        //生成过账单的日常费用要删除对应账单下的关联费项
        if (Objects.equals(dailyExpensesDO.getIsGenerateBill(), BooleanEnum.TRUE.getValue())) {
            ExpenseOrderItemDO orderItemDO = expenseOrderItemMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
                    .eq(ExpenseOrderItemDO::getSourceExpenseItemId, id)
                    .eq(ExpenseOrderItemDO::getExpenseSource, BusinessConstants.DAILY_EXPENSES));

            if (orderItemDO != null) {
                ExpenseOrderDO expenseOrderDO = expenseOrderMapper.selectById(orderItemDO.getExpenseOrderId());
                expenseOrderDO.setActualAmount(expenseOrderDO.getActualAmount().subtract(orderItemDO.getTotalAmount()));
                isPay = orderItemDO.getPayStatus().equals(BooleanEnum.TRUE.getValue());
                expenseOrderMapper.updateById(expenseOrderDO);
                expenseOrderItemMapper.deleteById(orderItemDO);
            }
        }
        updateRefundOrder(dailyExpensesDO,true,isPay);
        dailyExpensesMapper.deleteById(dailyExpensesDO);
        LogRecordContext.putVariable("dailyExpenses", dailyExpensesDO);

    }

    @Override
    @LogRecord(type = ELDERLY_DAILY_EXPENSES_TYPE, subType = ELDERLY_DAILY_EXPENSES_INSERT_SUB_TYPE, bizNo = "{{#elderId}}",
            success = ELDERLY_DAILY_EXPENSES_INSERT_SUCCESS, extra = "{{#elderId}}")
    public void supplementaryExpenses(DailyExpensesSaveReqVO updateReqVO) {

        Long elderId = updateReqVO.getElderId();
        String attributionBillTime = updateReqVO.getAttributionBillTime();
        //查询指定月份账单
        List<ExpenseOrderDO> expenseOrderList = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getBillingMonth, attributionBillTime)
                .eq(ExpenseOrderDO::getElderId, elderId).orderByDesc(ExpenseOrderDO::getCreatedTime));

        ExpenseOrderDO expenseOrder = null;

        if (null != expenseOrderList && expenseOrderList.size() > 0) {
            expenseOrder = expenseOrderList.get(0);
        }


        if (expenseOrder == null) {
            throw exception(EXPENSE_ORDER_IS_NOT_EXISTS);
        }

        //存在即补录到指定月份中
        List<DailyExpensesDO> dailyExpensesList = updateReqVO.getDailyExpenses();
        BigDecimal amount = BigDecimal.ZERO;
        for (DailyExpensesDO dailyExpenses : dailyExpensesList) {
            dailyExpenses.setElderId(elderId);
            dailyExpenses.setType(1); //1:日常费用
            dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
            dailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            dailyExpenses.setAttributionBillTime(attributionBillTime);
            dailyExpenses.setTenantId(expenseOrder.getTenantId());
            dailyExpensesMapper.insert(dailyExpenses);


            ExpenseOrderItemDO expenseOrderItem = new ExpenseOrderItemDO();
            expenseOrderItem.setExpenseOrderId(expenseOrder.getId());
            expenseOrderItem.setSourceExpenseItemId(dailyExpenses.getId());
            expenseOrderItem.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
            expenseOrderItem.setItemCategoryName(dailyExpenses.getItemCategory());
            expenseOrderItem.setItemName(dailyExpenses.getItemName());
            expenseOrderItem.setPrice(dailyExpenses.getPrice());
            expenseOrderItem.setActualPrice(dailyExpenses.getPrice());
            expenseOrderItem.setTotalAmount(dailyExpenses.getAmount());
            expenseOrderItem.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
            expenseOrderItem.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
            expenseOrderItem.setCount(dailyExpenses.getCount());
            expenseOrderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            expenseOrderItem.setCreatedTime(new Date());
            expenseOrderItem.setTenantId(dailyExpenses.getTenantId());
            expenseOrderItemMapper.insert(expenseOrderItem);

            amount = amount.add(expenseOrderItem.getTotalAmount());

//        } else {
//            dbDailyExpenses = new DailyExpensesDO();
//            dbDailyExpenses.setType(1); //1:日常
//            dbDailyExpenses.setElderId(elderId);
//            dbDailyExpenses.setAttributionBillTime(updateReqVO.getAttributionBillTime());
//            dbDailyExpenses.setAccountingTime(new Date());
//            dbDailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
//            dailyExpensesMapper.insert(dbDailyExpenses);
//        }
        }
        if (CollectionUtil.isNotEmpty(dailyExpensesList)) {
            expenseOrder.setPayStatus(BooleanEnum.FALSE.getValue());
            expenseOrder.setPayTime(null);
            expenseOrder.setActualAmount(expenseOrder.getActualAmount().add(amount));
            expenseOrderMapper.updateById(expenseOrder);
        }

        LogRecordContext.putVariable("elderId", elderId);
    }

    @Override
    public PageResult<DailyExpensesDO> getDailyExpensesPage(DailyExpensesPageReqVO pageReqVO) {
        Page<DailyExpensesDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<DailyExpensesDO> list = dailyExpensesMapper.getDailyExpensesPage(page, pageReqVO);
        Boolean isSelectBed = pageReqVO.getIsSelectBed() == null ? true : pageReqVO.getIsSelectBed();
        if (true == isSelectBed) {
            for (DailyExpensesDO dailyExpensesDO : list) {
                String fullBedName = buildService.getFullBedName(dailyExpensesDO.getElderId());
                dailyExpensesDO.setBedName(fullBedName);
                TenantDO tenantDO = tenantMapper.selectById(dailyExpensesDO.getTenantId());
                dailyExpensesDO.setTenantName(tenantDO == null ? null : tenantDO.getName());
            }
        }
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    @LogRecord(type = ELDERLY_DAILY_EXPENSES_TYPE, subType = ELDERLY_DAILY_EXPENSES_IMPORT_SUB_TYPE, bizNo = "1",
            success = ELDERLY_DAILY_EXPENSES_IMPORT_SUCCESS)
    @Transactional
    public Map<String, Object> importDailyExpensesExcel(List<DailyExpensesExcelVO> list) {
        Date currentTime = new Date();
        List<DailyExpensesExcelVO> errorList = new ArrayList<>();
        int successCount = 0;

        for (DailyExpensesExcelVO excelVO : list) {
            try {
                if (excelVO.getAttributionBillTime() == null || !excelVO.getAttributionBillTime().matches("^\\d{4}-(0[1-9]|1[0-2])$")) {
                    excelVO.setErrorMsg("归属账单月格式错误：" + excelVO.getAttributionBillTime() + "，必须是yyyy-MM格式，例如：2026-01");
                    errorList.add(excelVO);
                    continue;
                }
                // 验证并获取长者信息
                ElderlyInfoDO elderlyInfo = validateAndGetElderlyInfo(excelVO);
                if (elderlyInfo == null) {
                    excelVO.setErrorMsg("长者信息不存在");
                    errorList.add(excelVO);
                    continue;
                }

                // 验证并获取收费项目信息
                OverheadChargeDO overheadCharge = validateAndGetOverheadCharge(excelVO);
                if (overheadCharge == null) {
                    excelVO.setErrorMsg("收费项目不存在");
                    errorList.add(excelVO);
                    continue;
                }

                // 验证并获取收费分类信息
                SysChargeCategoryDO chargeCategory = validateAndGetChargeCategory(overheadCharge);
                if (chargeCategory == null) {
                    excelVO.setErrorMsg("收费分类不存在");
                    errorList.add(excelVO);
                    continue;
                }

                // 创建日常费用记录
                DailyExpensesDO dailyExpenses = createDailyExpensesRecord(excelVO, elderlyInfo, overheadCharge, chargeCategory, currentTime);

                // 如果有开始和结束时间，则需要生成账单
                if (excelVO.getStartDate() != null && excelVO.getEndDate() != null) {
                    // 将费用项添加到账单中
                    if (!processExpenseOrder(dailyExpenses, elderlyInfo)) {
                        excelVO.setErrorMsg("账单已确认或已缴费，无法自动带入到归属月账单中");
                        errorList.add(excelVO);
                        continue;
                    }
                }

                successCount++;
            } catch (Exception e) {
                log.error("导入异常: " + excelVO.getElderName(), e);
                excelVO.setErrorMsg("导入异常: " + e.getMessage());
                errorList.add(excelVO);
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("successCount", successCount);
        result.put("failCount", errorList.size());
        result.put("errorList", errorList);
        return result;
    }

    /**
     * 验证并获取长者信息
     */
    private ElderlyInfoDO validateAndGetElderlyInfo(DailyExpensesExcelVO excelVO) {
        return elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eqIfPresent(ElderlyInfoDO::getIdCard, excelVO.getIdCard())
                .eq(ElderlyInfoDO::getElderName, excelVO.getElderName())
                .eq(ElderlyInfoDO::getTenantId, TenantContextHolder.getTenantId())
                .eq(ElderlyInfoDO::getDeleted,BooleanEnum.FALSE.getValue())
                .eq(ElderlyInfoDO::getInStatus,BooleanEnum.TRUE.getValue()));
    }

    /**
     * 验证并获取收费项目信息
     */
    private OverheadChargeDO validateAndGetOverheadCharge(DailyExpensesExcelVO excelVO) {
        return sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
                .eq(OverheadChargeDO::getChargeName, excelVO.getItemName()));
    }

    /**
     * 验证并获取收费分类信息
     */
    private SysChargeCategoryDO validateAndGetChargeCategory(OverheadChargeDO overheadCharge) {
        return sysChargeCategoryMapper.selectById(overheadCharge.getSuperiorsId());
    }

    /**
     * 创建日常费用记录
     */
    private DailyExpensesDO createDailyExpensesRecord(DailyExpensesExcelVO excelVO,
                                                      ElderlyInfoDO elderlyInfo,
                                                      OverheadChargeDO overheadCharge,
                                                      SysChargeCategoryDO chargeCategory,
                                                      Date currentTime) {
        DailyExpensesDO dailyExpenses = new DailyExpensesDO();
        dailyExpenses.setCount(excelVO.getCount());
        dailyExpenses.setAccountingTime(currentTime);
        dailyExpenses.setCreatedTime(currentTime);
        dailyExpenses.setPrice(excelVO.getPrice());
        dailyExpenses.setElderId(elderlyInfo.getId());
        dailyExpenses.setItemName(excelVO.getItemName());
        dailyExpenses.setItemId(overheadCharge.getId());
        dailyExpenses.setType(excelVO.getExpenseSource());
        dailyExpenses.setRemarks(excelVO.getRemarks());
        dailyExpenses.setItemCategory(chargeCategory.getName());
        dailyExpenses.setAttributionBillTime(excelVO.getAttributionBillTime());
        dailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        dailyExpenses.setStartDate(excelVO.getStartDate());
        dailyExpenses.setEndDate(excelVO.getEndDate());

        // 计算总金额
        dailyExpenses.setAmount(excelVO.getPrice().multiply(BigDecimal.valueOf(excelVO.getCount()))
                .setScale(8, RoundingMode.DOWN));
        dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
        dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));

        dailyExpensesMapper.insert(dailyExpenses);
        return dailyExpenses;
    }

    /**
     * 处理费用账单
     */
    private boolean processExpenseOrder(DailyExpensesDO dailyExpenses, ElderlyInfoDO elderlyInfo) {
        // 查找对应月份的账单
        ExpenseOrderDO expenseOrder = expenseOrderMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getElderId, elderlyInfo.getId())
                .eq(ExpenseOrderDO::getBillingMonth, dailyExpenses.getAttributionBillTime())
                .eq(ExpenseOrderDO::getTenantId, elderlyInfo.getTenantId()));
        if (expenseOrder != null) {
            if(expenseOrder.getIsLock()){
                return false;
            }
            if(expenseOrder.getPayStatus() == 1){
                return false;
            }
            // 如果账单存在，添加费用项到现有账单
            addExpenseItemToExistingOrder(expenseOrder, dailyExpenses);
            dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
            dailyExpensesMapper.updateById(dailyExpenses);
        }
        return true;
    }

    /**
     * 添加费用项到现有账单
     */
    private void addExpenseItemToExistingOrder(ExpenseOrderDO expenseOrder, DailyExpensesDO dailyExpenses) {
        ExpenseOrderItemDO expenseOrderItem = createExpenseOrderItem(expenseOrder.getId(), dailyExpenses);
        expenseOrderItemMapper.insert(expenseOrderItem);

        // 更新账单金额
        BigDecimal updatedAmount = expenseOrder.getActualAmount().add(expenseOrderItem.getTotalAmount());
        expenseOrder.setActualAmount(updatedAmount);
        expenseOrderMapper.updateById(expenseOrder);
    }

    /**
     * 创建新账单
     */
    private void createNewExpenseOrder(DailyExpensesDO dailyExpenses, ElderlyInfoDO elderlyInfo) {
        ExpenseOrderDO expenseOrder = new ExpenseOrderDO();
        expenseOrder.setBillingMonth(dailyExpenses.getAttributionBillTime());
        expenseOrder.setCreatedTime(new Date());
        expenseOrder.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expenseOrder.setElderId(dailyExpenses.getElderId());
        expenseOrder.setBillOrderNumber("E" + RandomUtil.randomNumbers(16));
        expenseOrder.setType(2); // 月度账单
        expenseOrder.setActualAmount(BigDecimal.ZERO);
        expenseOrder.setOrgType(elderlyInfo.getOrgType());
        expenseOrder.setTenantId(elderlyInfo.getTenantId());
        expenseOrderMapper.insert(expenseOrder);

        ExpenseOrderItemDO expenseOrderItem = createExpenseOrderItem(expenseOrder.getId(), dailyExpenses);
        expenseOrderItemMapper.insert(expenseOrderItem);

        // 更新账单金额
        BigDecimal updatedAmount = expenseOrder.getActualAmount().add(expenseOrderItem.getTotalAmount());
        expenseOrder.setActualAmount(updatedAmount);
        expenseOrderMapper.updateById(expenseOrder);
    }

    /**
     * 创建费用项
     */
    private ExpenseOrderItemDO createExpenseOrderItem(Long expenseOrderId, DailyExpensesDO dailyExpenses) {
        ExpenseOrderItemDO expenseOrderItem = new ExpenseOrderItemDO();
        expenseOrderItem.setExpenseOrderId(expenseOrderId);
        expenseOrderItem.setSourceExpenseItemId(dailyExpenses.getId());
        expenseOrderItem.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
        expenseOrderItem.setItemCategoryName(dailyExpenses.getItemCategory());
        expenseOrderItem.setItemName(dailyExpenses.getItemName());
        expenseOrderItem.setPrice(dailyExpenses.getPrice());
        expenseOrderItem.setActualPrice(dailyExpenses.getPrice());
        expenseOrderItem.setTotalAmount(dailyExpenses.getAmount());
        expenseOrderItem.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
        expenseOrderItem.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
        expenseOrderItem.setCount(dailyExpenses.getCount());
        expenseOrderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expenseOrderItem.setCreatedTime(new Date());
        expenseOrderItem.setTenantId(dailyExpenses.getTenantId());
        expenseOrderItem.setDescription(dailyExpenses.getRemarks());
        return expenseOrderItem;
    }

    @Override
    public List<String> getBillingMonthByElderId(Long elderId) {
        List<ExpenseOrderDO> expenseOrderList = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getElderId, elderId)
                .orderByDesc(ExpenseOrderDO::getBillingMonth)
                .last("LIMIT 10"));
        return expenseOrderList
                .stream()
                .map(ExpenseOrderDO::getBillingMonth)
                .collect(Collectors.toList());
    }

    @Override
    public void editDailyExpensesMonth(DailyExpensesSaveReqVO updateReqVO) {
        List<DailyExpensesDO> dailyExpenses = updateReqVO.getDailyExpenses();
        for (DailyExpensesDO dailyExpense : dailyExpenses) {
            DailyExpensesDO dailyExpensesDO = dailyExpensesMapper.selectById(dailyExpense.getId());
            dailyExpensesDO.setAttributionBillTime(updateReqVO.getAttributionBillTime());
            dailyExpensesMapper.updateById(dailyExpensesDO);
        }
    }

    @Override
    public List<DailyExpensesDO> getMedicalDailyExpenses(DailyMedicalExpensesReqVO reqVO) {
        reqVO.setItemCategory("增值服务费");
        List<DailyExpensesDO> list = dailyExpensesMapper.getMedicalDailyExpenses(reqVO);
        list = list.stream().filter(e->(!e.getItemCategory().contains("电器管理费") || !e.getItemCategory().contains("洗衣费") || !e.getItemCategory().contains("电费"))).collect(Collectors.toList());
        HashMap<Long, List<DailyExpensesDO>> elderItemMap = new HashMap<>();
        for (DailyExpensesDO dailyExpensesDO : list) {
            List<DailyExpensesDO> dailyExpensesDOS = elderItemMap.computeIfAbsent(dailyExpensesDO.getElderId(), k -> new ArrayList<>());
            dailyExpensesDOS.add(dailyExpensesDO);
        }
        for (Map.Entry<Long, List<DailyExpensesDO>> entry : elderItemMap.entrySet()) {
            String fullBedName = buildService.getFullBedName(entry.getKey());
            for (DailyExpensesDO dailyExpensesDO : entry.getValue()) {
                dailyExpensesDO.setBedName(fullBedName);
            }
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void useMedicine(UseMedicineVO useMedicineVO) {
        Long elderId = useMedicineVO.getElderId();
        ElderlyInfoDO elder = elderlyInfoMapper.selectById(elderId);
        if (elder == null) {
            throw new RuntimeException("长者信息不存在");
        }

        List<MedicineRecordVO> medicineRecordList = useMedicineVO.getMedicineRecordList();
        if (CollectionUtil.isEmpty(medicineRecordList)) {
            return;
        }

        for (MedicineRecordVO medicineRecord : medicineRecordList) {
            // 1. 查询药品库存
            MedicineInventoryDO inventory = medicineInventoryService.getInventory(medicineRecord.getId());
            if (inventory == null) {
                throw new RuntimeException("药品库存不存在，ID: " + medicineRecord.getId());
            }

            // 检查库存是否充足
            int availableQuantity = inventory.getStockQuantity();
            if (availableQuantity < medicineRecord.getCount()) {
                throw new RuntimeException("药品库存不足，药品名称: " + inventory.getDrugName() + 
                        "，可用数量: " + availableQuantity + "，需要数量: " + medicineRecord.getCount());
            }
            // 扣减库存
            availableQuantity = availableQuantity - medicineRecord.getCount();
            inventory.setStockQuantity(availableQuantity);
            // 2. 增加已用数量
            Integer newUsedQuantity = (inventory.getUsedQuantity() == null ? 0 : inventory.getUsedQuantity()) + medicineRecord.getCount();
            inventory.setUsedQuantity(newUsedQuantity);
            medicineInventoryService.updateInventory(inventory);

            // 3. 生成药品出入库记录（出库，inOrOut=2）
            MedicineInOutRecordsDO inOutRecord = new MedicineInOutRecordsDO();
            inOutRecord.setBarcode(inventory.getBarcode());
            inOutRecord.setDrugName(inventory.getDrugName());
            inOutRecord.setBatchNumber(inventory.getBatchNumber());
            inOutRecord.setInOrOut(2); // 2-出库
            inOutRecord.setQuantity(medicineRecord.getCount());
            inOutRecord.setOperator(SecurityFrameworkUtils.getLoginUserNickname());
            inOutRecord.setTenantId(elder.getTenantId());
            medicineInOutRecordsService.createRecord(inOutRecord);

            // 4. 查询归属月账单是否已生成并且未缴费
            List<ExpenseOrderDO> expenseOrderList = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                    .eq(ExpenseOrderDO::getElderId, elderId)
                    .eq(ExpenseOrderDO::getBillingMonth, medicineRecord.getBillingMonth())
                    .eq(ExpenseOrderDO::getIsLock,Boolean.FALSE)
                    .ne(ExpenseOrderDO::getPayStatus, 1) // 未缴费
                    .in(ExpenseOrderDO::getType, 1, 2)); // 1：入院账单 2：月度账单

            // 5. 创建日常费用
            DailyExpensesDO dailyExpenses = new DailyExpensesDO();
            dailyExpenses.setElderId(elderId);
            dailyExpenses.setItemId(medicineRecord.getId());
            dailyExpenses.setItemCategory("药品费用");
            dailyExpenses.setItemName(inventory.getDrugName());
            dailyExpenses.setType(9); // 1:日常费用
            dailyExpenses.setPrice(medicineRecord.getPrice());
            dailyExpenses.setAmount(medicineRecord.getAmount());
            dailyExpenses.setRoundAmount(medicineRecord.getAmount().setScale(0, RoundingMode.HALF_UP));
            dailyExpenses.setRoundTwoDecimalAmount(medicineRecord.getAmount().setScale(2, RoundingMode.HALF_UP));
            dailyExpenses.setCount(medicineRecord.getCount());
            dailyExpenses.setRemarks(medicineRecord.getRemarks());
            dailyExpenses.setAttributionBillTime(medicineRecord.getBillingMonth());
            dailyExpenses.setTenantId(elder.getTenantId());
            dailyExpenses.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            dailyExpenses.setCreatedTime(new Date());
            if (medicineRecord.getAccountDate() != null) {
                dailyExpenses.setAccountingTime(medicineRecord.getAccountDate());
            }
            if (medicineRecord.getStartDate() != null) {
                dailyExpenses.setStartDate(medicineRecord.getStartDate());
            }
            if (medicineRecord.getEndDate() != null) {
                dailyExpenses.setEndDate(medicineRecord.getEndDate());
            }

            // 判断是否已生成账单且未缴费
            if (CollectionUtil.isNotEmpty(expenseOrderList)) {
                // 账单已生成且未缴费，设置 isGenerateBill 为 1，并自动把该日常费用带入到账单中
                ExpenseOrderDO expenseOrder = expenseOrderList.get(0);
                dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
                dailyExpensesMapper.insert(dailyExpenses);

                // 创建账单明细项
                ExpenseOrderItemDO expenseOrderItem = createExpenseOrderItem(expenseOrder.getId(), dailyExpenses);
                expenseOrderItemMapper.insert(expenseOrderItem);

                // 更新账单金额
                BigDecimal updatedAmount = expenseOrder.getActualAmount().add(expenseOrderItem.getTotalAmount());
                expenseOrder.setActualAmount(updatedAmount);
                expenseOrderMapper.updateById(expenseOrder);
            } else {
                // 账单未生成或已缴费，设置 isGenerateBill 为 0
                dailyExpenses.setIsGenerateBill(BooleanEnum.FALSE.getValue());
                dailyExpensesMapper.insert(dailyExpenses);
            }
        }
    }

    private void updateRefundOrder(DailyExpensesDO dailyExpensesDO,boolean isDelete, boolean isPay){
        if(isDelete){
            // 3. 查找所有与该该日常费用记录相关的退住账单明细项
            List<RefundSettlementOrderItemDO> refundOrderItems = refundSettlementOrderItemMapper.selectList(
                    new LambdaQueryWrapperX<RefundSettlementOrderItemDO>()
                            .notLike(RefundSettlementOrderItemDO::getItemName, "长护险")
                            .eq(RefundSettlementOrderItemDO::getSourceItemId, dailyExpensesDO.getId()));
            // 4. 删除所有相关的退住账单明细项并修正账单金额
            for (RefundSettlementOrderItemDO refundOrderItem : refundOrderItems) {
                RefundSettlementOrderDO refundSettlementOrder = refundSettlementOrderMapper.selectById(refundOrderItem.getRefundSettlementOrderId());
                if(isPay){
                    // 如果已缴费，那么将这个日常费用进行退费或者补费
                    refundOrderItem.setPrice(refundOrderItem.getPrice().negate());
                    refundOrderItem.setRefundAmount(dailyExpensesDO.getAmount().negate());
                    refundOrderItem.setActualRefundAmount(dailyExpensesDO.getAmount().negate());
                    if(refundSettlementOrder != null){
                        // 修正账单金额
                        // 对于缴费项目，删除，那么总金额就要减去该项目的费用
                        BigDecimal newAmount = refundSettlementOrder.getRefundAmount().add(refundOrderItem.getRefundAmount());
                        refundSettlementOrder.setRefundAmount(newAmount);
                        refundSettlementOrderMapper.updateById(refundSettlementOrder);
                    }
                    refundSettlementOrderItemMapper.updateById(refundOrderItem);
                }else {
                    if(refundSettlementOrder != null){
                        // 修正账单金额
                        // 对于缴费项目，删除，那么总金额就要减去该项目的费用
                        BigDecimal newAmount = refundSettlementOrder.getRefundAmount().subtract(refundOrderItem.getRefundAmount());
                        refundSettlementOrder.setRefundAmount(newAmount);
                        refundSettlementOrderMapper.updateById(refundSettlementOrder);
                    }
                    refundSettlementOrderItemMapper.deleteById(refundOrderItem);
                }
            }
        }else {
            // 查询对应退住的账单，如果不存在则返回
            List<RefundSettlementOrderDO> refundSettlementOrderDOList = refundSettlementOrderMapper.selectList(new LambdaQueryWrapperX<RefundSettlementOrderDO>()
                    .eq(RefundSettlementOrderDO::getElderId, dailyExpensesDO.getElderId())
                    .orderByDesc(RefundSettlementOrderDO::getCreatedTime)); // 月度账单
            if(CollectionUtil.isEmpty(refundSettlementOrderDOList)){
                return;
            }
            RefundSettlementOrderDO refundSettlementOrderDO = refundSettlementOrderDOList.get(0);

            // 创建账单费用项
            RefundSettlementOrderItemDO orderItem = new RefundSettlementOrderItemDO();
            orderItem.setRefundSettlementOrderId(refundSettlementOrderDO.getId());
            orderItem.setType(2);
            orderItem.setCount(dailyExpensesDO.getCount());
            orderItem.setItemName(dailyExpensesDO.getItemName());
            orderItem.setRemarks(dailyExpensesDO.getRemarks());
            orderItem.setPrice(dailyExpensesDO.getPrice()); // 单价
            orderItem.setRefundAmount(dailyExpensesDO.getAmount()); // 金额
            orderItem.setActualRefundAmount(dailyExpensesDO.getAmount()); // 总金额
            orderItem.setTenantId(dailyExpensesDO.getTenantId());
            orderItem.setSourceItemId(dailyExpensesDO.getId());
            refundSettlementOrderItemMapper.insert(orderItem);
            // 更新账单总金额
            BigDecimal currentAmount = refundSettlementOrderDO.getRefundAmount() != null ? refundSettlementOrderDO.getRefundAmount() : BigDecimal.ZERO;
            BigDecimal newAmount = currentAmount.add(orderItem.getRefundAmount());
            refundSettlementOrderDO.setRefundAmount(newAmount);
            refundSettlementOrderMapper.updateById(refundSettlementOrderDO);
        }
    }
}