package com.cool.store.service.privatesphere.impl;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.cool.store.constants.RedisConstant;
import com.cool.store.dao.StoreDao;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.oss.OssClientService;
import com.cool.store.request.privatesphere.PrivateSphereBindRequest;
import com.cool.store.request.privatesphere.PrivateSphereSnRequest;
import com.cool.store.service.privatesphere.PrivateSphereQrService;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.privatesphere.PrivateSphereVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * <p>
 * 私域二维码服务实现
 * </p>
 *
 * @author wangff
 * @since 2026/4/1
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PrivateSphereQrServiceImpl implements PrivateSphereQrService {

    private final RedisUtilPool redisUtilPool;
    private final OssClientService ossClientService;
    private final StoreDao storeDao;

    /**
     * 二维码尺寸
     */
    private static final int QR_CODE_SIZE = 1280;
    /**
     * sn缓存时间
     */
    private static final int SN_CACHE_TIME = 86400;
    /**
     * IP限制时间（1小时）
     */
    private static final int IP_LIMIT_TIME = 3600;
    /**
     * IP每小时最大生成次数
     */
    private static final int IP_MAX_COUNT = 5;

    @Override
    public PrivateSphereVO generateQrCode(PrivateSphereSnRequest request) {
        // 先从Redis中获取缓存
        String cachedUrl = redisUtilPool.hashGet(RedisConstant.PRIVATE_SN_QR_CODE, request.getSn());
        if (StringUtils.isNotBlank(cachedUrl)) {
            return new PrivateSphereVO(cachedUrl);
        }
        verify(request.getClientIp(), "rq_ge_limit");
        // 生成二维码并上传到OSS
        try {
            String qrCodeUrl = generateAndUploadQrCode(request.getSn());
            // 存储到Redis
            redisUtilPool.hashSet(RedisConstant.PRIVATE_SN_QR_CODE, request.getSn(), qrCodeUrl, SN_CACHE_TIME);
            log.info("生成二维码并上传成功，sn: {}, url: {}", request.getSn(), qrCodeUrl);
            return new PrivateSphereVO(qrCodeUrl);
        } catch (Exception e) {
            log.error("生成二维码失败，sn: {}", request.getSn(), e);
            return null;
        }
    }

    private void verify(String ip, String suffix) {
        // IP限制检查：同一IP一小时内最多生成5次
        if (StringUtils.isNotBlank(ip)) {
            String countStr = redisUtilPool.hashGet(RedisConstant.IP_LIMIT + "_" + suffix, ip);
            int count = StringUtils.isNotBlank(countStr) ? Integer.parseInt(countStr) : 0;
            if (count >= IP_MAX_COUNT) {
                log.error("IP生成次数超限，ip: {}, count: {}", ip, count);
                throw new ServiceException(ErrorCodeEnum.IP_LIMIT);
            }
            // 增加计数
            redisUtilPool.hashSet(RedisConstant.IP_LIMIT + "_" + suffix, ip, String.valueOf(count + 1), IP_LIMIT_TIME);
        }
    }

    @Override
    public Boolean bindStoreSn(PrivateSphereBindRequest request) {
        redisUtilPool.hashSet(RedisConstant.PRIVATE_STORE_SN_BIND, request.getSn(), request.getStoreId(), SN_CACHE_TIME);
        return true;
    }

    @Override
    public PrivateSphereVO getPrivateSphereQr(PrivateSphereSnRequest request) {
        String storeId = redisUtilPool.hashGet(RedisConstant.PRIVATE_STORE_SN_BIND, request.getSn());
        if (StringUtils.isBlank(storeId)) {
            return PrivateSphereVO.unbind();
        }
        String privateSphereQrCode = redisUtilPool.hashGet(RedisConstant.PRIVATE_STORE_SN_QR_CODE, request.getSn());
        if (privateSphereQrCode == null) {
            privateSphereQrCode = storeDao.getPrivateSphereQrCode(storeId);
            redisUtilPool.hashSet(RedisConstant.PRIVATE_STORE_SN_QR_CODE, request.getSn(), privateSphereQrCode == null ? "" : privateSphereQrCode, 120);
        }
        if (StringUtils.isBlank(privateSphereQrCode)) {
            return PrivateSphereVO.noMaintain();
        }
        return new PrivateSphereVO(privateSphereQrCode);
    }

    /**
     * 生成二维码并上传到OSS
     *
     * @param sn 二维码内容
     * @return OSS图片路径
     */
    private String generateAndUploadQrCode(String sn) throws Exception {
        // 配置二维码
        QrConfig qrConfig = new QrConfig(QR_CODE_SIZE, QR_CODE_SIZE);
        qrConfig.setMargin(2);

        // 生成二维码图片到内存
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        QrCodeUtil.generate(sn, qrConfig, "png", outputStream);

        String fileName = "qrcode" + sn + ".png";

        // 上传到OSS
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        long contentLength = outputStream.size();

        return ossClientService.putObjectWithoutPrefix(fileName, inputStream, contentLength, "image/png");
    }
}