package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.idev.excel.FastExcel;
import org.dromara.common.core.constant.BizConst;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.config.RedisUtil;
import org.dromara.system.domain.SysDictData;
import org.dromara.system.domain.SysDiseaseLabel;
import org.dromara.system.domain.SysFoodCategory;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.mapper.SysFoodCategoryMapper;
import org.dromara.system.service.ISysDictDataService;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.SysFoodIngredientBo;
import org.dromara.system.domain.vo.SysFoodIngredientVo;
import org.dromara.system.domain.SysFoodIngredient;
import org.dromara.system.mapper.SysFoodIngredientMapper;
import org.dromara.system.service.ISysFoodIngredientService;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 食材管理Service业务层处理
 *
 * @author Lion Li
 * @date 2025-06-30
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysFoodIngredientServiceImpl implements ISysFoodIngredientService {

    private final SysFoodIngredientMapper baseMapper;

    private final SysFoodCategoryMapper categoryMapper;

    private final ISysDictDataService dictDataService;

    /**
     * 查询食材管理
     *
     * @param foodIngredientId 主键
     * @return 食材管理
     */
    @Override
    public SysFoodIngredientVo queryById(Long foodIngredientId) {
        return baseMapper.selectVoById(foodIngredientId);
    }

    /**
     * 分页查询食材管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 食材管理分页列表
     */
    @Override
    public TableDataInfo<SysFoodIngredientVo> queryPageList(SysFoodIngredientBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysFoodIngredient> lqw = buildQueryWrapper(bo);
        Page<SysFoodIngredientVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        if (CollUtil.isNotEmpty(result.getRecords())) {
            Set<Long> ids = CollUtil.newHashSet();
            result.getRecords().forEach(v -> {
                Arrays.stream(v.getFoodCategoryId().split(",")).forEach(id -> {
                    ids.add(Long.valueOf(id));
                });
            });

            Map<String, SysDictDataVo> dictDataMap = dictDataService.selectMapByType(BizConst.FOOD_UNIT).getData();
            List<SysFoodCategory> categoryList = categoryMapper.selectList(Wrappers.lambdaQuery(SysFoodCategory.class)
                .in(SysFoodCategory::getFoodCategoryId, ids));
            Map<String, String> categoryMap = categoryList.stream().collect(Collectors.toMap(k1 -> String.valueOf(k1.getFoodCategoryId()), k2 -> k2.getName(), (k1, k2) -> k1));
            result.getRecords().forEach(v -> {
                String[] arr = v.getFoodCategoryId().split(",");
                if (arr.length >= 1) {
                    v.setBigCategory(categoryMap.get(arr[0]));
                }
                if (arr.length >= 2) {
                    v.setSubCategory(categoryMap.get(arr[1]));
                }
                SysDictDataVo unit = dictDataMap.get(v.getUnit());
                if (ObjUtil.isNotNull(unit)) {
                    v.setUnitName(unit.getDictLabel());
                }
            });
        }

        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的食材管理列表
     *
     * @param bo 查询条件
     * @return 食材管理列表
     */
    @Override
    public List<SysFoodIngredientVo> queryList(SysFoodIngredientBo bo) {
        LambdaQueryWrapper<SysFoodIngredient> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysFoodIngredient> buildQueryWrapper(SysFoodIngredientBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysFoodIngredient> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SysFoodIngredient::getFoodIngredientId);
//        lqw.eq(bo.getFoodCategoryId() != null, SysFoodIngredient::getFoodCategoryId, bo.getFoodCategoryId());
        if (StrUtil.isNotBlank(bo.getFoodCategoryId())) {
            lqw.apply("find_in_set({0},food_category_id)", bo.getFoodCategoryId());
        }
        lqw.like(StringUtils.isNotBlank(bo.getName()), SysFoodIngredient::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getCode()), SysFoodIngredient::getCode, bo.getCode());
        lqw.eq(StringUtils.isNotBlank(bo.getUnit()), SysFoodIngredient::getUnit, bo.getUnit());
        lqw.eq(bo.getPurchasePrice() != null, SysFoodIngredient::getPurchasePrice, bo.getPurchasePrice());
        lqw.eq(bo.getEdibleRatio() != null, SysFoodIngredient::getEdibleRatio, bo.getEdibleRatio());
        lqw.eq(bo.getShelfLife() != null, SysFoodIngredient::getShelfLife, bo.getShelfLife());
        lqw.eq(bo.getStockWarning() != null, SysFoodIngredient::getStockWarning, bo.getStockWarning());
        lqw.eq(bo.getExpiryWarning() != null, SysFoodIngredient::getExpiryWarning, bo.getExpiryWarning());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), SysFoodIngredient::getDescription, bo.getDescription());
        lqw.eq(bo.getCalories() != null, SysFoodIngredient::getCalories, bo.getCalories());
        lqw.eq(bo.getProtein() != null, SysFoodIngredient::getProtein, bo.getProtein());
        lqw.eq(bo.getFat() != null, SysFoodIngredient::getFat, bo.getFat());
        lqw.eq(bo.getCarbohydrate() != null, SysFoodIngredient::getCarbohydrate, bo.getCarbohydrate());
        lqw.eq(bo.getWater() != null, SysFoodIngredient::getWater, bo.getWater());
        lqw.eq(bo.getVitaminA() != null, SysFoodIngredient::getVitaminA, bo.getVitaminA());
        lqw.eq(bo.getVitaminB2() != null, SysFoodIngredient::getVitaminB2, bo.getVitaminB2());
        lqw.eq(bo.getVitaminC() != null, SysFoodIngredient::getVitaminC, bo.getVitaminC());
        lqw.eq(bo.getSodium() != null, SysFoodIngredient::getSodium, bo.getSodium());
        lqw.eq(bo.getIron() != null, SysFoodIngredient::getIron, bo.getIron());
        lqw.eq(bo.getPhosphorus() != null, SysFoodIngredient::getPhosphorus, bo.getPhosphorus());
        lqw.eq(bo.getDietaryFiber() != null, SysFoodIngredient::getDietaryFiber, bo.getDietaryFiber());
        lqw.eq(bo.getVitaminB1() != null, SysFoodIngredient::getVitaminB1, bo.getVitaminB1());
        lqw.eq(bo.getNiacin() != null, SysFoodIngredient::getNiacin, bo.getNiacin());
        lqw.eq(bo.getVitaminE() != null, SysFoodIngredient::getVitaminE, bo.getVitaminE());
        lqw.eq(bo.getCalcium() != null, SysFoodIngredient::getCalcium, bo.getCalcium());
        lqw.eq(bo.getPotassium() != null, SysFoodIngredient::getPotassium, bo.getPotassium());
        lqw.eq(bo.getCholesterol() != null, SysFoodIngredient::getCholesterol, bo.getCholesterol());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysFoodIngredient::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增食材管理
     *
     * @param bo 食材管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SysFoodIngredientBo bo) {
        SysFoodIngredient add = MapstructUtils.convert(bo, SysFoodIngredient.class);
        validEntityBeforeSave(add);
        add.setCode(RedisUtil.generateFoodCode());
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setFoodIngredientId(add.getFoodIngredientId());
        }
        return flag;
    }

    /**
     * 修改食材管理
     *
     * @param bo 食材管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SysFoodIngredientBo bo) {
        SysFoodIngredient update = MapstructUtils.convert(bo, SysFoodIngredient.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysFoodIngredient entity) {
        List<SysFoodIngredient> foodIngredients = baseMapper.selectList(Wrappers.lambdaQuery(SysFoodIngredient.class)
            .eq(SysFoodIngredient::getName, entity.getName()));
        if (ObjUtil.isNull(entity.getFoodIngredientId())) {
            if (CollUtil.isNotEmpty(foodIngredients)) {
                throw new ServiceException("食材名称已经存在!");
            }
        } else {
            if (foodIngredients.size() > 1) {
                throw new ServiceException("食材名称已经存在!");
            }
            if (!foodIngredients.get(0).getFoodIngredientId().equals(entity.getFoodIngredientId())) {
                throw new ServiceException("食材名称已经存在!");
            }
        }
    }

    /**
     * 校验并批量删除食材管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public R<?> importExcel(MultipartFile file) throws Exception {
        if (ObjUtil.isNull(file)) {
            return R.fail("请选择文件!");
        }

        List<Map<Integer, String>> excelList = FastExcel.read(file.getInputStream())
            .headRowNumber(3)
            .sheet().doReadSync();

        log.info("开始导入数据");
        if (CollUtil.isEmpty(excelList)) {
            return R.fail("读取数据为空!");
        }
        log.info("size:" + excelList.size());

        List<SysFoodCategory> categoryList = categoryMapper.selectList(
            Wrappers.lambdaQuery(SysFoodCategory.class).select(SysFoodCategory::getFoodCategoryId, SysFoodCategory::getName));
        Map<String, String> categoryMap = categoryList.stream()
            .collect(Collectors.toMap(k1 -> k1.getName(), k2 -> String.valueOf(k2.getFoodCategoryId()), (k1, k2) -> k1));
        List<SysFoodIngredient> foodList = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        excelList.forEach(v -> {
            if (MapUtil.isEmpty(v) || v.size() < 4) {
                builder.append(foodList.size() + 4).append("、");
                return;
            }
            SysFoodIngredient foodIngredient = new SysFoodIngredient();
            foodIngredient.setName(v.get(0));
            foodIngredient.setBigCategory(categoryMap.get(v.get(1)));
            foodIngredient.setSubCategory(categoryMap.get(v.get(2)));
            foodIngredient.setUnit(v.get(3));

            String colVal = v.get(4);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行4列、");
                    return;
                } else {
                    foodIngredient.setPurchasePrice(new BigDecimal(colVal));
                }
            }

            colVal = v.get(5);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行5列、");
                    return;
                } else {
                    foodIngredient.setEdibleRatio(new BigDecimal(colVal));
                }
            }

            colVal = v.get(6);
            if (StrUtil.isNotBlank(colVal)) {
                foodIngredient.setDescription(colVal);
            }

            colVal = v.get(7);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行7列、");
                    return;
                } else {
                    foodIngredient.setShelfLife(Long.valueOf(colVal));
                }
            }

            colVal = v.get(8);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行8列、");
                    return;
                } else {
                    foodIngredient.setExpiryWarning(Long.valueOf(colVal));
                }
            }

            colVal = v.get(9);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行9列、");
                    return;
                } else {
                    foodIngredient.setStockWarning(new BigDecimal(colVal));
                }
            }

            colVal = v.get(10);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行10列、");
                    return;
                } else {
                    foodIngredient.setCalories(new BigDecimal(colVal));
                }
            }

            colVal = v.get(11);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行11列、");
                    return;
                } else {
                    foodIngredient.setProtein(new BigDecimal(colVal));
                }
            }

            colVal = v.get(12);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行12列、");
                    return;
                } else {
                    foodIngredient.setFat(new BigDecimal(colVal));
                }
            }

            colVal = v.get(13);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行13列、");
                    return;
                } else {
                    foodIngredient.setCarbohydrate(new BigDecimal(colVal));
                }
            }

            colVal = v.get(14);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行14列、");
                    return;
                } else {
                    foodIngredient.setWater(new BigDecimal(colVal));
                }
            }

            colVal = v.get(15);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行15列、");
                    return;
                } else {
                    foodIngredient.setVitaminA(new BigDecimal(colVal));
                }
            }

            colVal = v.get(16);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行16列、");
                    return;
                } else {
                    foodIngredient.setVitaminB2(new BigDecimal(colVal));
                }
            }

            colVal = v.get(17);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行17列、");
                    return;
                } else {
                    foodIngredient.setVitaminC(new BigDecimal(colVal));
                }
            }

            colVal = v.get(18);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行18列、");
                    return;
                } else {
                    foodIngredient.setSodium(new BigDecimal(colVal));
                }
            }

            colVal = v.get(19);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行19列、");
                    return;
                } else {
                    foodIngredient.setIron(new BigDecimal(colVal));
                }
            }

            colVal = v.get(20);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行20列、");
                    return;
                } else {
                    foodIngredient.setPhosphorus(new BigDecimal(colVal));
                }
            }

            colVal = v.get(21);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行21列、");
                    return;
                } else {
                    foodIngredient.setDietaryFiber(new BigDecimal(colVal));
                }
            }

            colVal = v.get(22);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行22列、");
                    return;
                } else {
                    foodIngredient.setVitaminB1(new BigDecimal(colVal));
                }
            }

            colVal = v.get(23);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行23列、");
                    return;
                } else {
                    foodIngredient.setNiacin(new BigDecimal(colVal));
                }
            }

            colVal = v.get(24);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行24列、");
                    return;
                } else {
                    foodIngredient.setVitaminE(new BigDecimal(colVal));
                }
            }

            colVal = v.get(25);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行25列、");
                    return;
                } else {
                    foodIngredient.setCalcium(new BigDecimal(colVal));
                }
            }

            colVal = v.get(26);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("26、");
                    return;
                } else {
                    foodIngredient.setPotassium(new BigDecimal(colVal));
                }
            }

            colVal = v.get(27);
            if (StrUtil.isNotBlank(colVal)) {
                if (!NumberUtil.isNumber(colVal)) {
                    builder.append(foodList.size() + 4).append("行27列、");
                    return;
                } else {
                    foodIngredient.setCholesterol(new BigDecimal(colVal));
                }
            }

            if (StrUtil.isBlank(foodIngredient.getName()) || StrUtil.isBlank(foodIngredient.getBigCategory())
                || StrUtil.isBlank(foodIngredient.getSubCategory()) || StrUtil.isBlank(foodIngredient.getUnit())) {
                builder.append(foodList.size() + 4).append("、");
                return;
            }
            foodIngredient.setFoodCategoryId(foodIngredient.getBigCategory() + "," + foodIngredient.getSubCategory());
            foodList.add(foodIngredient);
        });

        if (builder.length() == 0) {
            foodList.forEach(fd -> {
                fd.setCode(RedisUtil.generateFoodCode());
            });
            baseMapper.insertBatch(foodList);
        } else {
            return R.fail("以下行数据不完整：" + builder);
        }

        return R.ok("导入成功！");
    }
}
