package com.ruoyi.oa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.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 com.ruoyi.oa.domain.bo.SysOaWarehouseDetailBo;
import com.ruoyi.oa.domain.bo.SysOaWarehouseMasterBo;
import com.ruoyi.oa.domain.dto.MonthlyStatsDTO;
import com.ruoyi.oa.domain.dto.SummaryFilterDTO;
import com.ruoyi.oa.domain.vo.SummaryCardVo;
import com.ruoyi.oa.mapper.SysOaWarehouseDetailMapper;
import com.ruoyi.oa.service.ISysOaWarehouseMasterService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.SysOaWarehouseBo;
import com.ruoyi.oa.domain.vo.SysOaWarehouseVo;
import com.ruoyi.oa.domain.SysOaWarehouse;
import com.ruoyi.oa.mapper.SysOaWarehouseMapper;
import com.ruoyi.oa.service.ISysOaWarehouseService;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 仓库管理Service业务层处理
 *
 * @author liuzongkun999
 * @date 2024-11-02
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysOaWarehouseServiceImpl implements ISysOaWarehouseService {

    private final SysOaWarehouseMapper baseMapper;

    private final SysOaWarehouseDetailMapper outWareMapper;

    private final ISysOaWarehouseMasterService masterService;

    /**
     * 查询仓库管理
     */
    @Override
    public SysOaWarehouseVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询仓库管理列表
     */
    @Override
    public TableDataInfo<SysOaWarehouseVo> queryPageList(SysOaWarehouseBo bo, PageQuery pageQuery) {
        QueryWrapper<SysOaWarehouse> lqw = new QueryWrapper<>();
        lqw.eq("sow.del_flag", 0);
        lqw.and(StringUtils.isNotBlank(bo.getName()), qw -> qw
                        .like("sow.name", bo.getName())
                        .or()
                        .like("sow.brand", bo.getName())
                        .or()
                        .like("sow.model", bo.getName())
                )
                .eq(StringUtils.isNotBlank(bo.getModel()), "sow.model", bo.getModel())
                .eq(StringUtils.isNotBlank(bo.getBrand()), "sow.brand", bo.getBrand());
        Page<SysOaWarehouseVo> result = baseMapper.selectListVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<SysOaWarehouseVo> queryPageListThreshold(SysOaWarehouseBo bo, PageQuery pageQuery, boolean b) {
        QueryWrapper<SysOaWarehouse> lqw = new QueryWrapper<>();
        lqw.eq("sow.del_flag", 0);
        if (b) {
            lqw.apply("sow.inventory < sow.threshold");
        } else {
            lqw.apply("sow.inventory >= sow.threshold");
        }
        lqw.eq(StringUtils.isNotBlank(bo.getModel()), "sow.model", bo.getModel());
        lqw.eq(StringUtils.isNotBlank(bo.getBrand()), "sow.brand", bo.getBrand());

        lqw.and(StringUtils.isNotBlank(bo.getName()), qw -> qw
                        .like("sow.name", bo.getName())
                        .or()
                        .like("sow.brand", bo.getName())
                        .or()
                        .like("sow.model", bo.getName())
                )
                .eq(StringUtils.isNotBlank(bo.getModel()), "sow.model", bo.getModel())
                .eq(StringUtils.isNotBlank(bo.getBrand()), "sow.brand", bo.getBrand());

        Page<SysOaWarehouseVo> result = baseMapper.selectListVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public Boolean insertBatch(List<SysOaWarehouseBo> boList) {
        SysOaWarehouseMasterBo sysOaWarehouseMaster = new SysOaWarehouseMasterBo();
        sysOaWarehouseMaster.setType(1L);
        List<SysOaWarehouseDetailBo> list = new ArrayList<>();
        boList.forEach(item -> {
            item.setInventory(item.getTaskInventory());
            SysOaWarehouseDetailBo bo = new SysOaWarehouseDetailBo();
            bo.setAmount(item.getInventory());
            bo.setSignPrice(item.getPrice());
            Long warehouseId = insertByBo2(item);
            bo.setWarehouseId(warehouseId);
            list.add(bo);

        });
        sysOaWarehouseMaster.setWarehouseList(list);
        sysOaWarehouseMaster.setMasterNum(UUID.randomUUID().toString());
        return masterService.insertByBo(sysOaWarehouseMaster);
    }


    /**
     * 查询仓库管理列表
     */
    @Override
    public List<SysOaWarehouseVo> queryList(SysOaWarehouseBo bo) {
        LambdaQueryWrapper<SysOaWarehouse> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public TableDataInfo<SysOaWarehouseVo> listByMultiQuery(SysOaWarehouseBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysOaWarehouse> lqw = buildQueryWrapper(bo);
        lqw.like(StringUtils.isNotBlank(bo.getName()), SysOaWarehouse::getName, bo.getName()).or()
                .like(StringUtils.isNotBlank(bo.getName()), SysOaWarehouse::getBrand, bo.getName()).or()
                .like(StringUtils.isNotBlank(bo.getName()), SysOaWarehouse::getModel, bo.getName());
        Page<SysOaWarehouseVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }


    private LambdaQueryWrapper<SysOaWarehouse> buildQueryWrapper(SysOaWarehouseBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysOaWarehouse> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getInventory() != null, SysOaWarehouse::getInventory, bo.getInventory());

        lqw.eq(StringUtils.isNotBlank(bo.getUnit()), SysOaWarehouse::getUnit, bo.getUnit());
        lqw.eq(StringUtils.isNotBlank(bo.getModel()), SysOaWarehouse::getModel, bo.getModel());
        lqw.like(StringUtils.isNotBlank(bo.getName()), SysOaWarehouse::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getBrand()), SysOaWarehouse::getBrand, bo.getBrand());
        lqw.eq(StringUtils.isNotBlank(bo.getSpecifications()), SysOaWarehouse::getSpecifications, bo.getSpecifications());
        return lqw;
    }

    /**
     * 新增仓库管理
     */
    @Override
    public Long insertByBo(SysOaWarehouseBo bo) {
        SysOaWarehouse add = BeanUtil.toBean(bo, SysOaWarehouse.class);
        validEntityBeforeSave(add);
        // 1、查询仓库中是否有已存在项目
        LambdaQueryWrapper<SysOaWarehouse> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysOaWarehouse::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getModel()), SysOaWarehouse::getModel, bo.getModel());
        SysOaWarehouse select = baseMapper.selectOne(lqw);
        // 2、 无则直接新增项目 有则直接增加库存数量
        Long flag;
        if (select == null) {
            baseMapper.insert(add);
            flag = add.getId();
        } else  {
            select.setInventory(select.getInventory() + bo.getInventory());
            if (bo.getPrice()!=null && bo.getPrice()>0) {
                select.setPrice((select.getPrice() * select.getInventory() + bo.getPrice() * bo.getInventory()) / (select.getInventory() + bo.getInventory()));
            }

            flag = select.getId();
        }

        return flag;
    }

    /**
     * 新增仓库管理
     */
    @Override
    public Long insertByBo2(SysOaWarehouseBo bo) {
        SysOaWarehouse add = BeanUtil.toBean(bo, SysOaWarehouse.class);
        validEntityBeforeSave(add);
        // 1、查询仓库中是否有已存在项目
        LambdaQueryWrapper<SysOaWarehouse> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysOaWarehouse::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getModel()), SysOaWarehouse::getModel, bo.getModel());
        SysOaWarehouse select = baseMapper.selectOne(lqw);
        // 2、 无则直接新增项目 有则直接增加库存数量
        if (select == null) {
            baseMapper.insert(add);
            return add.getId();
        } else {
            select.setInventory(select.getInventory() + bo.getTaskInventory());
            select.setPrice((select.getPrice() * select.getInventory() + bo.getPrice() * bo.getInventory()) / (select.getInventory() + bo.getInventory()));
            baseMapper.updateById(select);
            return select.getId();
        }

    }

    /**
     * 修改仓库管理
     */
    @Override
    public Boolean updateByBo(SysOaWarehouseBo bo) {
        SysOaWarehouse update = BeanUtil.toBean(bo, SysOaWarehouse.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysOaWarehouse entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除仓库管理
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }

        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public List<SysOaWarehouseVo> selectRecentOutbound(int limit) {
        return outWareMapper.selectRecentOutbound(limit);
    }

    @Override
    public List<SummaryCardVo> getSummaryCards(SummaryFilterDTO f) {
        // —— 1. 处理默认 endTime ——
        // 如果调用方没有传 endTime，则当日查询用当前时点
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = f.getEndTime() != null ? f.getEndTime() : now;
        f.setEndTime(end);

        // ① 快照时点库存
        Long endInv = baseMapper.selectInventoryAt(f);
        // ② 月份对比：如果同时传了 beginTime，则按 begin/end 计算环比
        double invTrend;
        if (f.getBeginTime() != null) {
            SummaryFilterDTO fb = new SummaryFilterDTO();
            fb.setEndTime(f.getBeginTime());
            fb.setName(f.getName());
            fb.setBrand(f.getBrand());
            fb.setSupplier(f.getSupplier());
            long beginInv = baseMapper.selectInventoryAt(fb);
            invTrend = ratio(endInv, beginInv);
        } else {
            // 回退：上月快照计算（例：CURDATE()-1月）
            SummaryFilterDTO fb = new SummaryFilterDTO();
            fb.setEndTime(f.getEndTime() != null
                    ? f.getEndTime().minusMonths(1)
                    : LocalDateTime.now().minusMonths(1));
            fb.setName(f.getName());
            fb.setBrand(f.getBrand());
            fb.setSupplier(f.getSupplier());
            long prevInv = baseMapper.selectInventoryAt(fb);
            invTrend = ratio(endInv, prevInv);
        }

        // ③ 在途
        long currTransit = baseMapper.selectInTransitBetween(f);
        // —— 上一周期在途（若有 beginTime/endTime，则平移同长度；否则前一天）
        long prevTransit;
        if (f.getBeginTime() != null && f.getEndTime() != null) {
            Duration dur = Duration.between(f.getBeginTime(), f.getEndTime());
            SummaryFilterDTO fp = new SummaryFilterDTO();
            fp.setBeginTime(f.getBeginTime().minus(dur));
            fp.setEndTime(f.getEndTime().minus(dur));
            fp.setName(f.getName());
            fp.setBrand(f.getBrand());
            fp.setSupplier(f.getSupplier());
            prevTransit = baseMapper.selectInTransitBetween(fp);
        } else {
            SummaryFilterDTO fp = new SummaryFilterDTO();
            fp.setEndTime(f.getEndTime() != null
                    ? f.getEndTime().minusDays(1)
                    : LocalDateTime.now().minusDays(1));
            fp.setName(f.getName());
            fp.setBrand(f.getBrand());
            fp.setSupplier(f.getSupplier());
            prevTransit = baseMapper.selectInTransitBetween(fp);
        }
        double transitTrend = ratio(currTransit, prevTransit);

        // ④ 当日入/出库 & 增长
        // 注意：此时 f.endTime 已经一定不为 null，selectInboundOn/selectOutboundOn 都是“当日”
        long todayIn = baseMapper.selectInboundOn(f);
        long todayOut = baseMapper.selectOutboundOn(f);

        // 前一天快照
        SummaryFilterDTO fPrev = new SummaryFilterDTO();
        fPrev.setEndTime(end.minusDays(1));
        fPrev.setBeginTime(null);   // 不影响“当日”接口
        fPrev.setName(f.getName());
        fPrev.setBrand(f.getBrand());
        fPrev.setSupplier(f.getSupplier());

        long prevIn = baseMapper.selectInboundOn(fPrev);
        long prevOut = baseMapper.selectOutboundOn(fPrev);

        double inTrend = ratio(todayIn, prevIn);
        double outTrend = ratio(todayOut, prevOut);

        // ⑤ 预警（默认是“当日”，因为我们一开始就把 f.endTime 设成了 today）
        int warnCount = baseMapper.selectWarningOn(f);

        // —— 拼装返回 ——
        List<SummaryCardVo> cards = new ArrayList<>();
        cards.add(new SummaryCardVo("当前总库存量", endInv, round(invTrend)));
        cards.add(new SummaryCardVo("在途物料数量", currTransit, round(transitTrend)));
        cards.add(new SummaryCardVo("当日入库量", todayIn, round(inTrend)));
        cards.add(new SummaryCardVo("当日出库量", todayOut, round(outTrend)));
        cards.add(new SummaryCardVo("预警信息", (long) warnCount, 0.0));
        return cards;
    }


    @Override
    public MonthlyStatsDTO getMonthlyStats(String ymStr) {
        // 1. 解析年月
        YearMonth ym = (ymStr != null && !ymStr.isEmpty())
                ? YearMonth.parse(ymStr, DateTimeFormatter.ofPattern("yyyy-MM"))
                : YearMonth.now();
        int year = ym.getYear();
        int month = ym.getMonthValue();

        // 2. 年度入/出库原始数据
        List<Map<String, Object>> inRaw = baseMapper.selectInboundByMonth(year);
        List<Map<String, Object>> outRaw = baseMapper.selectOutboundByMonth(year);

        // 3. 填充 12 个月的占位列表
        List<Long> inMonthList = new ArrayList<>(Collections.nCopies(12, 0L));
        List<Long> outMonthList = new ArrayList<>(Collections.nCopies(12, 0L));
        inRaw.forEach(r -> {
            int m = (Integer) r.get("month");
            long t = ((Number) r.get("total")).longValue();
            inMonthList.set(m - 1, t);
        });
        outRaw.forEach(r -> {
            int m = (Integer) r.get("month");
            long t = ((Number) r.get("total")).longValue();
            outMonthList.set(m - 1, t);
        });

        // 4. 当月按天库存快照
        int days = ym.lengthOfMonth();
        List<Long> snapList = new ArrayList<>(days);
        for (int d = 1; d <= days; d++) {
            LocalDate date = LocalDate.of(year, month, d);
            snapList.add(baseMapper.selectInventorySnapshot(date));
        }

        // 5. 封装返回
        MonthlyStatsDTO dto = new MonthlyStatsDTO();
        dto.setInData(Collections.singletonMap("月", inMonthList));
        dto.setOutData(Collections.singletonMap("月", outMonthList));
        dto.setDataMap(Collections.singletonMap("日", snapList));
        return dto;
    }

    /**
     * 计算环比，prev = 0 则返回 0
     */
    private double ratio(double curr, double prev) {
        if (prev == 0) return 0.0;
        return (curr - prev) / prev * 100;
    }

    /**
     * 四舍五入到 1 位小数
     */
    private double round(double v) {
        return BigDecimal.valueOf(v)
                .setScale(1, RoundingMode.HALF_UP)
                .doubleValue();
    }


}
