package cn.iocoder.yudao.module.identity.service.generaterecord;


import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.enums.CodeEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.qrcode.QrCodeUtil;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.basic.api.businessinfo.BusinessInfoApi;
import cn.iocoder.yudao.module.basic.api.dealerinfo.DealerInfoApi;
import cn.iocoder.yudao.module.basic.api.dealerinfo.dto.DealerInfoRespDTO;
import cn.iocoder.yudao.module.basic.api.redis.dto.BusinessInfoDTO;
import cn.iocoder.yudao.module.identity.controller.admin.generaterecord.vo.*;
import cn.iocoder.yudao.module.identity.convert.generaterecord.GenerateRecordConvert;
import cn.iocoder.yudao.module.identity.dal.dataobject.code.CodeDO;
import cn.iocoder.yudao.module.identity.dal.dataobject.generatebatch.GenerateBatchDO;
import cn.iocoder.yudao.module.identity.dal.dataobject.generaterecord.GenerateRecordDO;
import cn.iocoder.yudao.module.identity.dal.mysql.code.CodeMapper;
import cn.iocoder.yudao.module.identity.dal.mysql.generatebatch.GenerateBatchMapper;
import cn.iocoder.yudao.module.identity.dal.mysql.generaterecord.GenerateRecordMapper;
import cn.iocoder.yudao.module.identity.enums.BatchTypeEnums;
import cn.iocoder.yudao.module.identity.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.identity.enums.GenerateRecordStateEnums;
import cn.iocoder.yudao.module.identity.qrcode.QRCodeProperties;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.product.api.harvestbatch.HarvestBatchApi;
import cn.iocoder.yudao.module.product.api.harvestbatch.dto.HarvestBatchDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.identity.enums.ErrorCodeConstants.GENERATE_RECORD_NOT_EXISTS;

/**
 * 标识码生成记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class GenerateRecordServiceImpl implements GenerateRecordService {

    @Resource
    private GenerateRecordMapper generateRecordMapper;

    @Resource
    private GenerateBatchMapper generateBatchMapper;

    @Resource
    private CodeMapper codeMapper;

    @Resource
    private FileApi fileApi;

    @Resource
    private HarvestBatchApi harvestBatchApi;

    @Resource
    private BusinessInfoApi businessInfoApi;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private DealerInfoApi dealerInfoApi;

    @Resource
    private QRCodeProperties qrCodeProperties;

    /**
     * 创建标识码生成记录
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    @Override
    @Transactional
    public Long createGenerateRecord(GenerateRecordCreateReqVO createReqVO) {
        // 查询商户
        BusinessInfoDTO businessInfo = businessInfoApi.getBusinessInfoByBusinessId(createReqVO.getBusinessId()).getData();
        if(businessInfo == null) {
            throw ServiceExceptionUtil.exception(cn.iocoder.yudao.module.basic.enums.ErrorCodeConstants.BUSINESS_INFO_NOT_EXISTS);
        }

        // 查询批次
        HarvestBatchDTO harvestBatch = harvestBatchApi.getHarvestBatchById(createReqVO.getBatchId()).getData();
        if (harvestBatch == null) {
            throw ServiceExceptionUtil.exception(cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.HARVEST_BATCH_NOT_EXISTS);
        }

        // 查询经销商
        DealerInfoRespDTO dealerInfo = dealerInfoApi.getDealerInfoByGoods(createReqVO.getDealerId(), businessInfo.getId(), harvestBatch.getGoodsId()).getData();
        if(dealerInfo == null) {
            throw ServiceExceptionUtil.exception(cn.iocoder.yudao.module.basic.enums.ErrorCodeConstants.DEALER_INFO_NOT_EXISTS);
        }

        List<String> stringList = new ArrayList<>(StrUtils.getRandomStringList(createReqVO.getCharLength(), createReqVO.getCharType(), createReqVO.getCodeNum()));
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        String fileUrl;
        try {
            List<BufferedImage> bufferedImages = new ArrayList<>();
            for (String s : stringList) {
                BufferedImage bufferedImage = QrCodeUtil.createQrCode(qrCodeProperties.getUrl() + s, s);
                bufferedImages.add(bufferedImage);
            }
            QrCodeUtil.compressQrCodeToZip(bufferedImages, os);
            // 将输出流上传阿里云服务器
            fileUrl = fileApi.createFile(null, null, os.toByteArray());
            os.close();
        } catch (Exception e) {
            log.error("生成二维码失败，{}", e.getMessage(), e);
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.GENERATE_CODE_FAIL);
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        String imageFileUrl;
        try {
            List<BufferedImage> bufferedImages = new ArrayList<>();
            for (String s : stringList) {
                BufferedImage bufferedImage;
                bufferedImage = QrCodeUtil.createQrCode(qrCodeProperties.getUrl() + s, null);
                bufferedImages.add(bufferedImage);
            }
            QrCodeUtil.compressQrCodeToZip(bufferedImages, bos);
            // 将输出流上传阿里云服务器
            imageFileUrl = fileApi.createFile(null, null, bos.toByteArray());
            bos.close();
        } catch (Exception e) {
            log.error("生成二维码失败，{}", e.getMessage(), e);
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.GENERATE_CODE_FAIL);
        }

        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        assert user != null;
        AdminUserRespDTO adminUser = adminUserApi.getUser(user.getId()).getData();
        if(adminUser == null) {
            throw ServiceExceptionUtil.exception(cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS);
        }

        GenerateRecordDO generateRecord = new GenerateRecordDO();// 生成记录
        GenerateBatchDO generateBatchDO = new GenerateBatchDO();// 批次关联
        List<CodeDO> codeDOS = new ArrayList<>(); // 标识码集合

        // 封装生成记录
        BeanUtil.copyProperties(createReqVO, generateRecord);
        generateRecord.setFileUrl(fileUrl);
        generateRecord.setImageFileUrl(imageFileUrl);
        generateRecord.setGenerateRecordId(CodeEnum.CODE_CODE.getCode());
        generateRecord.setOperateUser(adminUser.getNickname());
        generateRecord.setOperateUserId(SecurityFrameworkUtils.getLoginUserId());
        generateRecord.setBelongBusinessId(businessInfo.getId());
        generateRecord.setBelongBusinessName(businessInfo.getBusinessName());
        // 因为非异步，这边直接设置成已生成
        generateRecord.setState(GenerateRecordStateEnums.ALL_COMPLETED.getState());

        // 封装关联表
        generateBatchDO.setGenerateRecordId(generateRecord.getGenerateRecordId());
        generateBatchDO.setBelongBusinessId(generateRecord.getBelongBusinessId());
        generateBatchDO.setBelongBusinessName(generateRecord.getBelongBusinessName());
        generateBatchDO.setBatchType(BatchTypeEnums.HARVEST_BATCH.getBatchType());
        generateBatchDO.setNum(createReqVO.getCodeNum());
        generateBatchDO.setBatchId(createReqVO.getBatchId());

        // 循环生成的二维码 并封装要插入数据库的数据
        for (String s : stringList) {
            CodeDO codeDO = new CodeDO();
            codeDO.setGenerateRecordId(generateRecord.getGenerateRecordId());
            codeDO.setIdentityCode(s);
            codeDO.setCharLength(createReqVO.getCharLength());
            codeDO.setCharType(createReqVO.getCharType());
            codeDO.setBatchId(harvestBatch.getHarvestBatchId());
            codeDO.setBatchType(BatchTypeEnums.HARVEST_BATCH.getBatchType());
            codeDO.setGoodsId(harvestBatch.getGoodsId());
            codeDO.setGoodsName(harvestBatch.getGoodsName());
            codeDO.setDealerId(dealerInfo.getDealerId());
            codeDO.setDealerName(dealerInfo.getDealerName());
            codeDO.setBelongBusinessId(generateRecord.getBelongBusinessId());
            codeDO.setBelongBusinessName(generateRecord.getBelongBusinessName());

            codeDOS.add(codeDO);
        }

        //新增主表
        generateRecordMapper.insert(generateRecord);

        //新增子表数据
        generateBatchMapper.insert(generateBatchDO);

        //新增标识码数据
        codeMapper.insertBatch(codeDOS);

        // 返回
        return generateRecord.getId();
    }

    /**
     * 根据 generateRecordId记录编码查询出该条数据信息
     *
     */
    @Override
    public GenerateRecordDO getGenerateRecordByRecordId(String generateRecordId) {
        // 使用MyBatis的selectOne方法执行查询操作，根据generateRecordId查询对应的记录
        return generateRecordMapper.selectOne(new QueryWrapper<GenerateRecordDO>().eq("generate_record_id", generateRecordId));
    }


    /**
     * 更新标识码生成记录
     *
     * @param updateReqVO 更新信息
     */
    @Override
    public void updateGenerateRecord(GenerateRecordUpdateReqVO updateReqVO) {
        // 校验存在
        validateGenerateRecordExists(updateReqVO.getId());
        // 更新
        GenerateRecordDO updateObj = GenerateRecordConvert.INSTANCE.convert(updateReqVO);
        generateRecordMapper.updateById(updateObj);
    }

    /**
     * 删除标识码生成记录
     *
     * @param id 编号
     */
    @Override
    public void deleteGenerateRecord(Long id) {
        //校验存在
        GenerateRecordDO generateRecordInfo = generateRecordMapper.selectById(id);
        if (generateRecordInfo == null){
            throw exception(GENERATE_RECORD_NOT_EXISTS);
        }
        // 删除
        generateRecordMapper.deleteById(id);
    }

    private void validateGenerateRecordExists(Long id) {
        if (generateRecordMapper.selectById(id) == null) {
            throw exception(GENERATE_RECORD_NOT_EXISTS);
        }
    }

    /**
     * 获得标识码生成记录
     *
     * @param id 编号
     * @return 标识码生成记录
     */
    @Override
    public GenerateRecordDO getGenerateRecord(Long id) {
        return generateRecordMapper.selectById(id);
    }

    /**
     * 获得标识码生成记录列表
     *
     * @param ids 编号
     * @return 标识码生成记录列表
     */
    @Override
    public List<GenerateRecordDO> getGenerateRecordList(Collection<Long> ids) {
        return generateRecordMapper.selectBatchIds(ids);
    }

    /**
     * 获得标识码生成记录分页
     *
     * @param pageReqVO 分页查询
     * @return 标识码生成记录分页
     */
    @Override
    public PageResult<GenerateRecordRespVO> getGenerateRecordPage(GenerateRecordPageReqVO pageReqVO) {
        // 执行分页查询
        Page<GenerateRecordRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<GenerateRecordRespVO> generateRecordList = generateRecordMapper.getPageList(page, pageReqVO);
        PageResult<GenerateRecordRespVO> pageResult = new PageResult<>();
        // 更新补充信息后的分页结果列表
        pageResult.setList(generateRecordList);
        pageResult.setTotal(page.getTotal());
        return pageResult;
    }

    /**
     * 获得标识码生成记录列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 标识码生成记录列表
     */
    @Override
    public List<GenerateRecordDO> getGenerateRecordList(GenerateRecordExportReqVO exportReqVO) {
        return generateRecordMapper.selectList(exportReqVO);
    }

}
