package com.openhis.web.inventorymanage.appservice.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.core.common.utils.poi.ExcelUtil;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.common.core.domain.R;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.enums.TenantOptionDict;
import com.core.common.utils.DateUtils;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
import com.core.web.util.TenantOptionUtil;
import com.openhis.administration.domain.ChargeItemDefDetail;
import com.openhis.administration.service.IChargeItemDefDetailService;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.*;
import com.openhis.common.enums.ybenums.YbChrgitmLv;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.web.inventorymanage.appservice.IProductDetailAppService;
import com.openhis.web.inventorymanage.dto.ProductDetailInitDto;
import com.openhis.web.inventorymanage.dto.ProductDetailPageDto;
import com.openhis.web.inventorymanage.dto.ProductDetailSearchParam;
import com.openhis.web.inventorymanage.mapper.ProductDetailAppMapper;
import com.openhis.web.reportmanage.utils.ExcelFillerUtil;
import com.openhis.workflow.domain.InventoryItem;
import com.openhis.workflow.mapper.InventoryItemMapper;

/**
 * 库存商品明细 impl
 *
 * @author yuanzs
 * @date 2025-04-24
 */
@Service
public class ProductDetailAppServiceImpl extends ServiceImpl<InventoryItemMapper, InventoryItem>
    implements IProductDetailAppService {

    @Resource
    private ProductDetailAppMapper productDetailsMapper;

    @Resource
    private IChargeItemDefDetailService chargeItemDefDetailService;

    /**
     * 库存商品明细初始化
     *
     * @return 下拉列表值
     */
    @Override
    public R<?> getInit() {
        ProductDetailInitDto productDetailInitDto = new ProductDetailInitDto();
        // 医保等级List
        List<ProductDetailInitDto.statusEnumOption> chrgitmLvOptions = Stream.of(InsuranceLevel.values())
            .map(status -> new ProductDetailInitDto.statusEnumOption(status.getValue(), status.getInfo()))
            .collect(Collectors.toList());
        productDetailInitDto.setChrgitmLvOptions(chrgitmLvOptions);
        return R.ok(productDetailInitDto);
    }

    /**
     * 查询库存商品明细分页列表
     *
     * @param productDetailSearchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @return 库存商品明细分页列表
     */
    @Override
    public R<?> getProductDetailPage(ProductDetailSearchParam productDetailSearchParam, Integer pageNo,
        Integer pageSize, String searchKey, HttpServletRequest request) {
        // 项目类型
        Integer categoryCode = productDetailSearchParam.getCategoryCode();
        // 库存是否为零
        Integer zeroFlag = productDetailSearchParam.getZeroFlag();
        // 过期天数
        Integer remainingDays = productDetailSearchParam.getRemainingDays();
        // 所在库房
        List<Long> locationIds = productDetailSearchParam.getLocationIds();
        // 供应商
        List<Long> supplierIds = productDetailSearchParam.getSupplierIds();
        productDetailSearchParam.setCategoryCode(null).setZeroFlag(null).setRemainingDays(null).setLocationIds(null)
            .setSupplierIds(null);
        // 构建查询条件
        QueryWrapper<ProductDetailSearchParam> queryWrapper = HisQueryUtils.buildQueryWrapper(
            productDetailSearchParam, searchKey, new HashSet<>(Arrays.asList(CommonConstants.FieldName.ItemName,
                CommonConstants.FieldName.BusNo, CommonConstants.FieldName.PyStr, CommonConstants.FieldName.WbStr)),
            request);
        // 根据不同分类拼接查询条件
        if (categoryCode != null) {
            if (categoryCode.equals(ItemCategoryCode.CHINESE_PATENT_DRUG.getValue())
                || categoryCode.equals(ItemCategoryCode.WESTERN_MEDICINE.getValue())
                || categoryCode.equals(ItemCategoryCode.EXTERNALLY_PROCURED_DRUGS.getValue())
                || categoryCode.equals(ItemCategoryCode.CHINESE_HERBAL_MEDICINE.getValue())) {
                queryWrapper.eq(CommonConstants.FieldName.ItemTable,
                    CommonConstants.TableName.MED_MEDICATION_DEFINITION);
                queryWrapper.eq(CommonConstants.FieldName.MedCategoryCode, categoryCode.toString());
            } else if (categoryCode.equals(ItemCategoryCode.DEVICE.getValue())) {
                queryWrapper.eq(CommonConstants.FieldName.ItemTable, CommonConstants.TableName.ADM_DEVICE_DEFINITION);
            }
        }
        // 库存是否为零
        if (zeroFlag != null) {
            if (Whether.YES.getValue().equals(zeroFlag)) {
                queryWrapper.eq(CommonConstants.FieldName.Quantity, BigDecimal.ZERO);
            } else {
                queryWrapper.gt(CommonConstants.FieldName.Quantity, BigDecimal.ZERO);
            }
        }
        // 所在位置
        if (locationIds != null && !locationIds.isEmpty()) {
            queryWrapper.in(CommonConstants.FieldName.LocationId, locationIds);
        }
        // 供应商
        if (supplierIds != null && !supplierIds.isEmpty()) {
            queryWrapper.in(CommonConstants.FieldName.SupplierId, supplierIds);
        }
        // 过期天数
        if (remainingDays != null) {
            queryWrapper.le(CommonConstants.FieldName.RemainingDays, remainingDays);
        }
        // 查询库存商品明细分页列表
        Page<ProductDetailPageDto> productDetailsPage = productDetailsMapper.selectProductDetailsPage(
            new Page<>(pageNo, pageSize), queryWrapper, CommonConstants.TableName.MED_MEDICATION_DEFINITION,
            CommonConstants.TableName.ADM_DEVICE_DEFINITION, ConditionCode.LOT_NUMBER_COST.getCode());
        // 库存明细
        List<ProductDetailPageDto> productDetailList = productDetailsPage.getRecords();
        if (productDetailList != null && !productDetailList.isEmpty()) {
            // 医嘱定价来源
            String orderPricingSource = TenantOptionUtil.getOptionContent(TenantOptionDict.ORDER_PRICING_SOURCE);
            // 批次售价需查询定价子表
            if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
                // 收集所有定价ID
                List<Long> chargeItemDefIdList =
                    productDetailList.stream().map(ProductDetailPageDto::getChargeItemDefId).filter(Objects::nonNull)
                        .distinct().collect(Collectors.toList());

                // 查询批次售价信息
                if (!chargeItemDefIdList.isEmpty()) {
                    List<ChargeItemDefDetail> lotNumberPriceList =
                        chargeItemDefDetailService.getLotNumberPriceByDefIds(chargeItemDefIdList);
                    if (lotNumberPriceList != null && !lotNumberPriceList.isEmpty()) {
                        // 创建批次号到售价的映射
                        Map<String, BigDecimal> lotPriceMap =
                            lotNumberPriceList.stream().collect(Collectors.toMap(ChargeItemDefDetail::getConditionValue,
                                ChargeItemDefDetail::getAmount, (existing, replacement) -> existing)); // 处理重复键的情况

                        // 更新原始列表中的售价
                        for (ProductDetailPageDto productDetail : productDetailList) {
                            BigDecimal price = lotPriceMap.get(productDetail.getLotNumber());
                            if (price != null) {
                                productDetail.setTotalSalePrice(price);
                            }
                        }
                    }
                }
            }

            for (ProductDetailPageDto productDetailPageDto : productDetailList) {
                // 医保等级
                productDetailPageDto.setChrgitmLv_enumText(
                    EnumUtils.getInfoByValue(YbChrgitmLv.class, productDetailPageDto.getChrgitmLv()));
                // 停供状态
                productDetailPageDto.setInventoryStatusEnum_enumText(
                    EnumUtils.getInfoByValue(PublicationStatus.class, productDetailPageDto.getInventoryStatusEnum()));

                // 计算包装单位数量
                BigDecimal[] results =
                    productDetailPageDto.getQuantity().divideAndRemainder(productDetailPageDto.getPartPercent());
                // 整数
                productDetailPageDto.setNumber(results[0]);
                // 余数
                productDetailPageDto.setRemainder(results[1]);

                // 计算采购总额
                if (productDetailPageDto.getPurchasePrice() != null) {
                    productDetailPageDto
                        .setTotalPurchasePrice(productDetailPageDto.getPurchasePrice().multiply(results[0])
                            .add(productDetailPageDto.getPurchasePrice()
                                .divide(productDetailPageDto.getPartPercent(), 6, RoundingMode.HALF_UP)
                                .multiply(results[1])));
                }

                // 计算售价总额
                if (productDetailPageDto.getSalePrice() != null) {
                    productDetailPageDto.setTotalSalePrice(productDetailPageDto.getSalePrice().multiply(results[0])
                        .add(productDetailPageDto.getSalePrice()
                            .divide(productDetailPageDto.getPartPercent(), 6, RoundingMode.HALF_UP)
                            .multiply(results[1])));
                }
            }
        }
        return R.ok(productDetailsPage);
    }

    /**
     * 查询库存商品明细统计数据
     *
     * @param productDetailSearchParam 查询条件
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @return 库存商品明细统计数据
     */
    @Override
    public R<?> getProductDetailStatistics(ProductDetailSearchParam productDetailSearchParam, String searchKey,
        HttpServletRequest request) {
        // 查询库存商品明细分页列表
        R<?> result = this.getProductDetailPage(productDetailSearchParam, 1, 30000, searchKey, request);
        ProductDetailPageDto productDetail = new ProductDetailPageDto();
        if (result != null && result.getData() != null) {
            Page<ProductDetailPageDto> productDetailPage = (Page<ProductDetailPageDto>)result.getData();
            List<ProductDetailPageDto> productDetailList = productDetailPage.getRecords();
            // 统计库房总金额
            productDetail
                .setPurchasePriceStatistics(productDetailList.stream().map(ProductDetailPageDto::getTotalPurchasePrice)
                    .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add))
                .setSalePriceStatistics(productDetailList.stream().map(ProductDetailPageDto::getTotalSalePrice)
                    .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
        }
        return R.ok(productDetail);
    }

    /**
     * 操作：停供
     *
     * @param inventoryId 库存项目管理ID
     * @return 操作结果
     */
    @Override
    public R<?> stopSupplyById(Long inventoryId) {

        // 获取当前时间
        Date now = DateUtils.getNowDate();
        // 当前登录账号
        LoginUser loginUser = SecurityUtils.getLoginUser();

        // 停供按钮压下，更新库存项目管理表的库存状态：已停供
        int updateCount = baseMapper.update(null,
            new LambdaUpdateWrapper<InventoryItem>().eq(InventoryItem::getId, inventoryId)
                .set(InventoryItem::getUpdateTime, now).set(InventoryItem::getUpdateBy, loginUser.getUserId())
                .set(InventoryItem::getInventoryStatusEnum, PublicationStatus.RETIRED.getValue()));

        return updateCount > 0 ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null))
            : R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
    }

    /**
     * 操作：取消停供
     *
     * @param inventoryId 库存项目管理ID
     * @return 操作结果
     */
    @Override
    public R<?> cancelSupplyById(Long inventoryId) {

        // 获取当前时间
        Date now = DateUtils.getNowDate();
        // 当前登录账号
        LoginUser loginUser = SecurityUtils.getLoginUser();

        // 取消停供按钮压下，更新库存项目管理表的库存状态：未停供
        int updateCount = baseMapper.update(null,
            new LambdaUpdateWrapper<InventoryItem>().eq(InventoryItem::getId, inventoryId)
                .set(InventoryItem::getUpdateTime, now).set(InventoryItem::getUpdateBy, loginUser.getUserId())
                .set(InventoryItem::getInventoryStatusEnum, PublicationStatus.ACTIVE.getValue()));

        return updateCount > 0 ? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, null))
            : R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
    }

    /**
     * 库存明细表导出
     *
     * @param productDetailSearchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @param response 响应数据
     */
    public void makeExcelFile(ProductDetailSearchParam productDetailSearchParam, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request, HttpServletResponse response) {
        R<?> result = this.getProductDetailPageX(productDetailSearchParam, 1, 10000, searchKey, request);
        if (result != null && result.getData() != null) {
            Page<ProductDetailPageDto> pageData = (Page)result.getData();
            List<ProductDetailPageDto> dataList = pageData.getRecords();

            try {
                for(ProductDetailPageDto productDetailPageDto : dataList) {
                    // 获取单位
                    String unitCode = productDetailPageDto.getUnitCodeDictText();
                    String minUnitCode = productDetailPageDto.getMinUnitCodeDictText();
                    //获取数量
                    BigDecimal number = productDetailPageDto.getNumber();
                    BigDecimal remainder = productDetailPageDto.getRemainder();
                    // 拼接
                    if (remainder.compareTo(BigDecimal.ZERO) > 0) {
                        productDetailPageDto.setNumber_text(number.setScale(0, RoundingMode.HALF_UP) + unitCode + remainder.setScale(0, RoundingMode.HALF_UP) + minUnitCode);
                    } else {
                        productDetailPageDto.setNumber_text(number.setScale(0, RoundingMode.HALF_UP) + unitCode);
                    }
                    productDetailPageDto.setQuantity_text(productDetailPageDto.getQuantity().setScale(0, RoundingMode.HALF_UP) + minUnitCode);

                    // 金额字段拼接 ‘元’
                    BigDecimal purchasePrice = productDetailPageDto.getPurchasePrice();
                    BigDecimal salePrice = productDetailPageDto.getSalePrice();
                    BigDecimal totalPurchasePrice = productDetailPageDto.getTotalPurchasePrice();
                    BigDecimal totalSalePrice = productDetailPageDto.getTotalSalePrice();
                    if (salePrice != null) {
                        productDetailPageDto.setExcelSalePrice(salePrice.setScale(2, RoundingMode.HALF_UP) + "元");
                    }

                    if (purchasePrice != null) {
                        productDetailPageDto.setExcelPurchasePrice(purchasePrice.setScale(2, RoundingMode.HALF_UP) + "元");
                    }

                    if (totalPurchasePrice != null) {
                        productDetailPageDto.setExcelTotalPurchasePrice(totalPurchasePrice.setScale(2, RoundingMode.HALF_UP) + "元");
                    }

                    if (totalSalePrice != null) {
                        productDetailPageDto.setExcelTotalSalePrice(totalSalePrice.setScale(2, RoundingMode.HALF_UP) + "元");
                    }

                    // 判断项目类别
                    String devCategoryCodeDictText = productDetailPageDto.getDevCategoryCodeDictText();
                    String medCategoryCodeDictText = productDetailPageDto.getMedCategoryCodeDictText();
                    String categoryCodeDictText = devCategoryCodeDictText == null ? medCategoryCodeDictText : devCategoryCodeDictText;
                    productDetailPageDto.setCategoryCodeDictText(categoryCodeDictText);
                }

                //导出
                ExcelUtil<ProductDetailPageDto> util = new ExcelUtil(ProductDetailPageDto.class);
                util.exportExcel(response, dataList, "库存明细记录");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.printf("导出Excel失败：" + e.getMessage());
            }
        }

    }


    /**
     * 查询库存商品明细分页列表，联查数据字典
     *
     * @param productDetailSearchParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @return 库存商品明细分页列表
     */
    public R<?> getProductDetailPageX(ProductDetailSearchParam productDetailSearchParam, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request) {
        Integer categoryCode = productDetailSearchParam.getCategoryCode();
        Integer zeroFlag = productDetailSearchParam.getZeroFlag();
        Integer remainingDays = productDetailSearchParam.getRemainingDays();
        List<Long> locationIds = productDetailSearchParam.getLocationIds();
        List<Long> supplierIds = productDetailSearchParam.getSupplierIds();
        productDetailSearchParam.setCategoryCode((Integer)null).setZeroFlag((Integer)null).setRemainingDays((Integer)null).setLocationIds((List)null).setSupplierIds((List)null);
        QueryWrapper<ProductDetailSearchParam> queryWrapper = HisQueryUtils.buildQueryWrapper(productDetailSearchParam, searchKey, new HashSet(Arrays.asList("item_name", "bus_no", "py_str", "wb_str")), request);
        if (categoryCode != null) {
            if (!categoryCode.equals(ItemCategoryCode.CHINESE_PATENT_DRUG.getValue()) && !categoryCode.equals(ItemCategoryCode.WESTERN_MEDICINE.getValue()) && !categoryCode.equals(ItemCategoryCode.EXTERNALLY_PROCURED_DRUGS.getValue()) && !categoryCode.equals(ItemCategoryCode.CHINESE_HERBAL_MEDICINE.getValue())) {
                if (categoryCode.equals(ItemCategoryCode.DEVICE.getValue())) {
                    queryWrapper.eq("item_table", "adm_device_definition");
                }
            } else {
                queryWrapper.eq("item_table", "med_medication_definition");
                queryWrapper.eq("med_category_code", categoryCode.toString());
            }
        }

        if (zeroFlag != null) {
            if (Whether.YES.getValue().equals(zeroFlag)) {
                queryWrapper.eq("quantity", BigDecimal.ZERO);
            } else {
                queryWrapper.gt("quantity", BigDecimal.ZERO);
            }
        }

        if (locationIds != null && !locationIds.isEmpty()) {
            queryWrapper.in("location_id", locationIds);
        }

        if (supplierIds != null && !supplierIds.isEmpty()) {
            queryWrapper.in("supplier_id", supplierIds);
        }

        if (remainingDays != null) {
            queryWrapper.le("remaining_days", remainingDays);
        }

        Page<ProductDetailPageDto> productDetailsPage = this.productDetailsMapper.selectProductDetailsPageX(new Page((long)pageNo, (long)pageSize), queryWrapper, "med_medication_definition", "adm_device_definition", ConditionCode.LOT_NUMBER_COST.getCode());
        List<ProductDetailPageDto> productDetailList = productDetailsPage.getRecords();
        if (productDetailList != null && !productDetailList.isEmpty()) {
            String orderPricingSource = TenantOptionUtil.getOptionContent(TenantOptionDict.ORDER_PRICING_SOURCE);
            if (OrderPricingSource.BATCH_SELLING_PRICE.getCode().equals(orderPricingSource)) {
                List<Long> chargeItemDefIdList = (List)productDetailList.stream().map(ProductDetailPageDto::getChargeItemDefId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
                if (!chargeItemDefIdList.isEmpty()) {
                    List<ChargeItemDefDetail> lotNumberPriceList = this.chargeItemDefDetailService.getLotNumberPriceByDefIds(chargeItemDefIdList);
                    if (lotNumberPriceList != null && !lotNumberPriceList.isEmpty()) {
                        Map<String, BigDecimal> lotPriceMap = (Map)lotNumberPriceList.stream().collect(Collectors.toMap(ChargeItemDefDetail::getConditionValue, ChargeItemDefDetail::getAmount, (existing, replacement) -> existing));

                        for(ProductDetailPageDto productDetail : productDetailList) {
                            BigDecimal price = (BigDecimal)lotPriceMap.get(productDetail.getLotNumber());
                            if (price != null) {
                                productDetail.setTotalSalePrice(price);
                            }
                        }
                    }
                }
            }

            for(ProductDetailPageDto productDetailPageDto : productDetailList) {
                productDetailPageDto.setChrgitmLv_enumText(EnumUtils.getInfoByValue(YbChrgitmLv.class, productDetailPageDto.getChrgitmLv()));
                productDetailPageDto.setInventoryStatusEnum_enumText(EnumUtils.getInfoByValue(PublicationStatus.class, productDetailPageDto.getInventoryStatusEnum()));
                BigDecimal[] results = productDetailPageDto.getQuantity().divideAndRemainder(productDetailPageDto.getPartPercent());
                productDetailPageDto.setNumber(results[0]);
                productDetailPageDto.setRemainder(results[1]);
                if (productDetailPageDto.getPurchasePrice() != null) {
                    productDetailPageDto.setTotalPurchasePrice(productDetailPageDto.getPurchasePrice().multiply(results[0]).add(productDetailPageDto.getPurchasePrice().divide(productDetailPageDto.getPartPercent(), 4, RoundingMode.HALF_UP).multiply(results[1])));
                }

                if (productDetailPageDto.getSalePrice() != null) {
                    productDetailPageDto.setTotalSalePrice(productDetailPageDto.getSalePrice().multiply(results[0]).add(productDetailPageDto.getSalePrice().divide(productDetailPageDto.getPartPercent(), 4, RoundingMode.HALF_UP).multiply(results[1])));
                }
            }
        }

        return R.ok(productDetailsPage);
    }


}
