package com.yida.data.system.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Joiner;
import com.yida.data.common.core.entity.ReceiveMsg;
import com.yida.data.common.core.entity.constant.AppConstant;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.*;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.core.utils.WxPublicUtil;
import com.yida.data.common.core.utils.WxUtil;
import com.yida.data.school.vo.smart.WxConfigVO;
import com.yida.data.system.mapper.EduSysFileMapper;
import com.yida.data.system.repository.ReceiveMsgRepository;
import com.yida.data.system.service.CommonService;
import com.yida.data.system.service.IDeptService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.TreeMap;

@Service
@RefreshScope
@Slf4j
@RequiredArgsConstructor
public class CommonServiceImpl implements CommonService {

    private final IDeptService deptService;

    private final EduSysFileMapper eduSysFileMapper;
    private final ReceiveMsgRepository receiveMsgRepository;
    private final com.yida.data.common.service.CommonService commonService;

    private final WxUtil wxUtil;
    private final WxPublicUtil wxPublicUtil;
    private final RedisService redisService;

    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    // 单次保存最大数量
    private final static Long SAVE_RECEIVE_MAX_SIZE = 1000L;

    @Override
    public EduSysFile upload(MultipartFile file) {
        EduSysFile sysFile = new EduSysFile();
        // 上传到本地
        String path = FileUtil.uploadMultipartFile(file);
        File localFile = new File(path);
        // md5校验文件是否存在
        String md5 = SecureUtil.md5(localFile);
        EduSysFile exist = eduSysFileMapper
            .selectOne(Wrappers.lambdaQuery(new EduSysFile()).eq(EduSysFile::getMd5, md5));
        if (exist != null) {
            localFile.delete();
            return exist;
        }
        // 文件数据入库
        sysFile.setOriginName(file.getOriginalFilename());
        sysFile.setFileSize(localFile.length());
        sysFile.setMd5(md5);
        // 上传到媒资
        String url = FileUtil.uploadFileToMediaServer(uploadUrl, path);
        // 视频文件保存封面
        if (FileUtil.isVideo(cn.hutool.core.io.FileUtil.getSuffix(sysFile.getOriginName()))) {
            sysFile.setCoverUrl(url.split(",")[1]);
        }
        sysFile.setUrl(url.split(",")[0]);
        eduSysFileMapper.insert(sysFile);
        localFile.delete();
        return sysFile;
    }

    @Override
    public String uploadImg(String code) {
        String path = FileUtil.uploadBase64Img(code, "png");
        File file = new File(path);
        if (file.length() > 10 * 1024 * 1024) {
            // 循环压缩到1000kb以下
            try {
                while ((new File(path).length() / 1024 / 1024) > 10) {
                    Thumbnails.of(path).scale(0.5).toFile(path);
                }
            } catch (Exception e) {
                log.error("压缩失败,msg:[{}],stack:[{}]", e.getMessage(), e.getStackTrace());
            }
        }
        File localFile = new File(path);
        // md5校验文件是否存在
        String md5 = SecureUtil.md5(localFile);
        EduSysFile exist = eduSysFileMapper
            .selectOne(Wrappers.lambdaQuery(new EduSysFile()).eq(EduSysFile::getMd5, md5));
        if (exist != null) {
            localFile.delete();
            return exist.getUrl();
        }
        EduSysFile sysFile = new EduSysFile();
        // 文件数据入库
        sysFile.setOriginName(StrUtil.uuid().replace("-", "") + ".png");
        sysFile.setFileSize(localFile.length());
        sysFile.setMd5(md5);
        // 上传到媒资
        String url = FileUtil.uploadFileToMediaServer(uploadUrl, path);
        sysFile.setUrl(url.split(",")[0]);
        eduSysFileMapper.insert(sysFile);
        localFile.delete();
        return url;
    }

    @Override
    public void saveReceiveMsg() {
        Long size = redisService.lGetListSize(CachePrefixConstant.RECEIVE_MSG);
        if (size > 0) {
            // 保存的数量
            long saveSize = Math.min(size, SAVE_RECEIVE_MAX_SIZE);
            List<ReceiveMsg> saveData = new ArrayList<>();
            // 保存后删除数据
            for (int i = 0; i < saveSize; i++) {
                ReceiveMsg msg = (ReceiveMsg) redisService.lLeftPop(CachePrefixConstant.RECEIVE_MSG);
                if (msg != null) {
                    saveData.add(msg);
                }
            }
            receiveMsgRepository.saveAll(saveData);
            log.info("保存{}条接收数据", saveSize);
        }
    }

    @Override
    public WxConfigVO getWxJsConfig(Long deptId, String url) {
        Dept dept = deptService.getById(deptId);
        if (Objects.isNull(dept)) {
            throw new FebsException("当前学校配置信息错误！");
        }
        // 获取应用信息
        EduApp app = commonService.getAppByCodeAndSchool(AppConstant.CONTACT_SELECT, null, deptId);
        String jsApiTicket = wxUtil.getJsApiTicket(wxUtil.getAccessToken(app.getWxCorpId(), app.getWxSecret()), deptId);
        // 时间戳
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        // 随机字符串
        String nonceStr = RandomUtil.randomString(32);

        // 请求参数
        JSONObject jsonObject = JSONUtil.createObj()
            .set("jsapi_ticket", jsApiTicket)
            .set("timestamp", timestamp)
            .set("noncestr", nonceStr)
            .set("url", url);
        TreeMap<String, Object> paramMap = MapUtil.sort(jsonObject);
        // 处理请求参数
        String paramsStr = Joiner.on("&").withKeyValueSeparator("=").join(paramMap);
        // 签名
        String signature = SecureUtil.sha1(paramsStr);
        return WxConfigVO.builder()
            .appId(dept.getCorpId())
            .timestamp(timestamp)
            .nonceStr(nonceStr)
            .signature(signature)
            .build();
    }

    @Override
    public WxConfigVO getWxPublicJsConfig(Long deptId, String url) {

        Dept dept = deptService.getById(deptId);
        if (Objects.isNull(dept)) {
            throw new FebsException("当前学校配置信息错误！");
        }
        String jsApiTicket = wxPublicUtil.getJsApiTicket(dept.getWxPublicAppId(), dept.getWxPublicSecret());
        // 时间戳
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        // 随机字符串
        String nonceStr = RandomUtil.randomString(32);

        // 请求参数
        JSONObject jsonObject = JSONUtil.createObj()
            .set("jsapi_ticket", jsApiTicket)
            .set("timestamp", timestamp)
            .set("noncestr", nonceStr)
            .set("url", url);
        TreeMap<String, Object> paramMap = MapUtil.sort(jsonObject);
        // 处理请求参数
        String paramsStr = Joiner.on("&").withKeyValueSeparator("=").join(paramMap);
        // 签名
        String signature = SecureUtil.sha1(paramsStr);
        return WxConfigVO.builder()
            .appId(dept.getWxPublicAppId())
            .timestamp(timestamp)
            .nonceStr(nonceStr)
            .signature(signature)
            .build();
    }
}
