package com.ruoyi.web.modules.stock.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.goods.domain.BizGoods;
import com.ruoyi.web.modules.goods.mapper.BizGoodsMapper;
import com.ruoyi.web.modules.stock.constant.StockConstants;
import com.ruoyi.web.modules.stock.domain.BizStockAdjust;
import com.ruoyi.web.modules.stock.domain.BizStockLog;
import com.ruoyi.web.modules.stock.dto.StockAdjustCreateDTO;
import com.ruoyi.web.modules.stock.dto.StockAdjustQuery;
import com.ruoyi.web.modules.stock.dto.StockAdjustRecordQuery;
import com.ruoyi.web.modules.stock.mapper.BizStockAdjustMapper;
import com.ruoyi.web.modules.stock.service.IStockAdjustService;
import com.ruoyi.web.modules.stock.service.IStockLogService;
import com.ruoyi.web.modules.stock.support.StockSupport;
import com.ruoyi.web.modules.stock.vo.StockAdjustListRowVO;
import com.ruoyi.web.modules.stock.vo.StockAdjustRecordRowVO;
import com.ruoyi.web.modules.stock.vo.StockQueryListRowVO;

@Service
public class StockAdjustServiceImpl implements IStockAdjustService
{
    @Autowired
    private BizGoodsMapper goodsMapper;

    @Autowired
    private BizStockAdjustMapper adjustMapper;

    @Autowired
    private IStockLogService stockLogService;

    @Autowired
    private StockSupport stockSupport;

    @Override
    public List<StockAdjustListRowVO> selectList(Long shopId, StockAdjustQuery query)
    {
        String keyword = query != null ? query.getKeyword() : null;
        List<StockQueryListRowVO> rows = goodsMapper.selectStockQueryList(shopId, keyword);
        if (rows == null || rows.isEmpty())
        {
            return Collections.emptyList();
        }
        List<StockAdjustListRowVO> result = new ArrayList<>(rows.size());
        for (StockQueryListRowVO row : rows)
        {
            StockAdjustListRowVO item = new StockAdjustListRowVO();
            item.setGoodsId(row.getGoodsId());
            item.setGoodsName(row.getGoodsName());
            item.setMainPic(row.getMainPic());
            item.setSpecText(stockSupport.normalizeSpecText(stockSupport.buildSpecText(row.getGoodsId())));
            result.add(item);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> confirmAdjust(Long shopId, Long goodsId, StockAdjustCreateDTO dto, Long operatorId,
            String operatorName)
    {
        validateCreateDto(dto);
        BizGoods goods = goodsMapper.selectByIdAndShopForUpdate(goodsId, shopId);
        if (goods == null)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_GOODS_INVALID);
        }

        int stockBefore = goods.getStock() != null ? goods.getStock() : 0;
        int inputQty = dto.getAdjustQty();
        String adjustMode = dto.getAdjustMode();
        int stockAfter;
        String adjustType;

        if (StockConstants.ADJUST_MODE_INCREMENT.equals(adjustMode))
        {
            if (inputQty == 0)
            {
                throw new ServiceException(StockConstants.MSG_ADJUST_QTY_ZERO);
            }
            stockAfter = stockBefore + inputQty;
            adjustType = inputQty > 0 ? StockConstants.ADJUST_TYPE_INCREASE : StockConstants.ADJUST_TYPE_DECREASE;
        }
        else
        {
            stockAfter = inputQty;
            adjustType = StockConstants.ADJUST_TYPE_OVERRIDE;
        }

        if (stockAfter < 0)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_STOCK_NEGATIVE);
        }

        int rows = goodsMapper.setStockForAdjust(goodsId, shopId, stockAfter);
        if (rows <= 0)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_GOODS_INVALID);
        }

        Date now = new Date();
        String specText = stockSupport.normalizeSpecText(stockSupport.buildSpecText(goodsId));

        BizStockAdjust adjust = new BizStockAdjust();
        adjust.setShopId(shopId);
        adjust.setGoodsId(goodsId);
        adjust.setGoodsName(goods.getGoodsName());
        adjust.setSpecText(specText);
        adjust.setAdjustMode(adjustMode);
        adjust.setAdjustType(adjustType);
        adjust.setAdjustQty(inputQty);
        adjust.setStockBefore(stockBefore);
        adjust.setStockAfter(stockAfter);
        adjust.setOperatorId(operatorId);
        adjust.setOperatorName(StringUtils.nvl(operatorName, ""));
        adjust.setCreateTime(now);
        adjustMapper.insert(adjust);

        int changeQty = Math.abs(stockAfter - stockBefore);
        String direction = stockAfter >= stockBefore ? StockConstants.DIRECTION_IN : StockConstants.DIRECTION_OUT;

        BizStockLog log = new BizStockLog();
        log.setShopId(shopId);
        log.setGoodsId(goodsId);
        log.setGoodsName(goods.getGoodsName());
        log.setSpecText(specText);
        log.setDirection(direction);
        log.setChangeReason(StockConstants.REASON_STOCK_EDIT);
        log.setChangeQty(changeQty);
        log.setStockBefore(stockBefore);
        log.setStockAfter(stockAfter);
        log.setRefType(StockConstants.REF_TYPE_ADJUST);
        log.setRefId(adjust.getAdjustId());
        log.setOperatorId(operatorId);
        log.setOperatorName(StringUtils.nvl(operatorName, ""));
        log.setCreateTime(now);
        stockLogService.insertLog(log);

        Map<String, Object> data = new HashMap<>(8);
        data.put("adjustId", adjust.getAdjustId());
        data.put("stockBefore", stockBefore);
        data.put("stockAfter", stockAfter);
        data.put("adjustType", adjustType);
        data.put("adjustTypeText", stockSupport.adjustTypeText(adjustType));
        return data;
    }

    @Override
    public List<StockAdjustRecordRowVO> listRecords(Long shopId, Long goodsId, StockAdjustRecordQuery query)
    {
        BizGoods goods = goodsMapper.selectByIdAndShop(goodsId, shopId);
        if (goods == null)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_GOODS_INVALID);
        }
        String adjustType = query != null ? query.getAdjustType() : null;
        List<StockAdjustRecordRowVO> rows = adjustMapper.selectByGoodsId(shopId, goodsId, adjustType);
        if (rows == null || rows.isEmpty())
        {
            return Collections.emptyList();
        }
        for (StockAdjustRecordRowVO row : rows)
        {
            row.setAdjustTypeText(stockSupport.adjustTypeText(row.getAdjustType()));
        }
        return rows;
    }

    private void validateCreateDto(StockAdjustCreateDTO dto)
    {
        if (dto == null || StringUtils.isEmpty(dto.getAdjustMode()))
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_MODE_REQUIRED);
        }
        if (!StockConstants.ADJUST_MODE_INCREMENT.equals(dto.getAdjustMode())
                && !StockConstants.ADJUST_MODE_OVERRIDE.equals(dto.getAdjustMode()))
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_MODE_INVALID);
        }
        if (dto.getAdjustQty() == null)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_QTY_REQUIRED);
        }
        if (StockConstants.ADJUST_MODE_OVERRIDE.equals(dto.getAdjustMode()) && dto.getAdjustQty() < 0)
        {
            throw new ServiceException(StockConstants.MSG_ADJUST_QTY_INVALID);
        }
    }
}
