package com.liquidnet.service.platform.service.impl.goblin;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.PageHelper;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.AdamUserInfoDto;
import com.liquidnet.service.adam.mapper.AdamUserMapper;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.CodeExcelVo;
import com.liquidnet.service.goblin.dto.vo.GoblinNftExCodeFetchExcelVo;
import com.liquidnet.service.goblin.dto.vo.GoblinNftExCodeVo;
import com.liquidnet.service.goblin.dto.vo.PageInfoVo;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import com.liquidnet.service.goblin.entity.GoblinNftExCode;
import com.liquidnet.service.goblin.entity.GoblinNftExSku;
import com.liquidnet.service.goblin.mapper.GoblinGoodsSkuMapper;
import com.liquidnet.service.goblin.mapper.GoblinNftExCodeMapper;
import com.liquidnet.service.goblin.mapper.GoblinNftExSkuMapper;
import com.liquidnet.service.goblin.param.GoblinNftExCodeParam;
import com.liquidnet.service.goblin.service.IGoblinNftExCodeService;
import com.liquidnet.service.platform.utils.GoblinRedisUtils;
import com.liquidnet.service.platform.utils.ObjectUtil;
import com.liquidnet.service.platform.utils.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * @Author: wll
 * @Description:
 * @Date:Create：in 2022/4/20 5:36 下午
 */
@Service
@Slf4j
public class GoblinNftExCodeServiceImpl implements IGoblinNftExCodeService {
    @Autowired
    private RedisDataSourceUtil redisDataSourceUtil;
    @Autowired
    private GoblinGoodsSkuMapper goblinGoodsSkuMapper;
    @Autowired
    private GoblinNftExCodeMapper goblinNftExCodeMapper;
    @Autowired
    private GoblinNftExSkuMapper goblinNftExSkuMapper;
    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private AdamUserMapper adamUserMapper;
    @Value("${liquidnet.service.order.url}")
    private String orderUrl;
    @Autowired
    private QueueUtils queueUtils;

    @Override
    public PageInfoVo selectCodePageList(GoblinNftExCodeParam goblinNftExCodeParam) {

        // 入参
        GoblinNftExCode goblinNftExCode = GoblinNftExCode.getNew();
        goblinNftExCode.setCode(goblinNftExCodeParam.getCode());
        goblinNftExCode.setActivityId(goblinNftExCodeParam.getActivityId());
        goblinNftExCode.setState(goblinNftExCodeParam.getState());
        goblinNftExCode.setRedeemUid(goblinNftExCodeParam.getUserId());
        goblinNftExCode.setIsDrivi(goblinNftExCodeParam.getIsDrivi());
        if (StringUtil.isNotBlank(goblinNftExCodeParam.getSkuName())) {
            // 根据藏品名称获取 skuIds
            String skuName = goblinNftExCodeParam.getSkuName();
            List<GoblinGoodsSku> goblinGoodsSkus = goblinGoodsSkuMapper.selectSkuLikeName(skuName);
            if (goblinGoodsSkus.size() <= 0) {
                return PageInfoVo.getNew();
            }
            StringBuffer skuIds = new StringBuffer();
            for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkus) {
                skuIds.append(goblinGoodsSku.getSkuId()).append(",");
            }
            goblinNftExCode.setSkuId(skuIds.deleteCharAt(skuIds.length() - 1).toString());
        }


        PageHelper.startPage(goblinNftExCodeParam.getPageNum(), 20, true);
        List<GoblinNftExCode> goblinNftExCodes = goblinNftExCodeMapper.selectGoblinNftCode(goblinNftExCode);

        int count = goblinNftExCodeMapper.selectGoblinNftCodeCount(goblinNftExCode);

        StringBuffer skuIds = new StringBuffer();
        StringBuffer acticityIds = new StringBuffer();
        for (GoblinNftExCode gnc : goblinNftExCodes) {
            skuIds.append(gnc.getSkuId()).append(",");
            if (StringUtil.isNotBlank(gnc.getBoxSkuId())) {
                skuIds.append(gnc.getBoxSkuId()).append(",");
            }
            acticityIds.append(gnc.getActivityId()).append(",");
        }

        // 获取返回对象实例
        ArrayList<GoblinNftExCodeVo> goblinNftExCodeArrayList = ObjectUtil.getGoblinNftExCodeVoArrayList();

        if (StringUtil.isNotBlank(skuIds)) {
            // 批量查询
            List<GoblinGoodsSku> goblinGoodsSkus = goblinGoodsSkuMapper.selectBySkuIds(skuIds.toString());
            for (GoblinNftExCode gnc : goblinNftExCodes) {
                GoblinNftExCodeVo goblinNftExCodeVo = GoblinNftExCodeVo.getNew().copy(gnc);
                for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkus) {
                    if (goblinNftExCodeVo.getSkuId().equals(goblinGoodsSku.getSkuId())) {
                        goblinNftExCodeVo.setSkuName(goblinGoodsSku.getName());
                    }

                    if (gnc.getState().equals(2)) {
                        if (StringUtil.isNotBlank(gnc.getBoxSkuId()) && gnc.getBoxSkuId().equals(goblinGoodsSku.getSkuId())) {
                            goblinNftExCodeVo.setResultSkuName(goblinGoodsSku.getName());
                        } else if (StringUtil.isBlank(gnc.getBoxSkuId()) && gnc.getSkuId().equals(goblinGoodsSku.getSkuId())) {
                            goblinNftExCodeVo.setResultSkuName(goblinGoodsSku.getName());
                        }
                    }
                }
                goblinNftExCodeArrayList.add(goblinNftExCodeVo);
            }
        }


        // 根据活动ids 获取兑换活动和sku的关联
        List<GoblinNftExSku> goblinNftExSkus = goblinNftExSkuMapper.selectGoblinNftExSkuByActivityIds(acticityIds.toString());


        HashSet<String> skuIdSet = CollectionUtil.getStringArraySet();
        for (GoblinNftExSku goblinNftExSku : goblinNftExSkus) {
            skuIdSet.add(goblinNftExSku.getSkuId());
        }


        LocalDateTime now = LocalDateTime.now();
        for (GoblinNftExCodeVo gnc : goblinNftExCodeArrayList) {
            for (GoblinNftExSku goblinNftExSku : goblinNftExSkus) {
                if (gnc.getActivityId().equals(goblinNftExSku.getActivityId())) {
                    if (StringUtil.isNotBlank(gnc.getBoxSkuId()) && gnc.getSkuId().equals(goblinNftExSku.getSkuId())) {
                        gnc.setExStartTime(goblinNftExSku.getExStartTime());
                        gnc.setExStopTime(goblinNftExSku.getExStopTime());
                        if (now.isAfter(goblinNftExSku.getExStopTime()) && !gnc.getState().equals(2)) {
                            gnc.setState(3);
                        }
                        break;
                    } else {
                        if (gnc.getSkuId().equals(goblinNftExSku.getSkuId())) {
                            gnc.setExStartTime(goblinNftExSku.getExStartTime());
                            gnc.setExStopTime(goblinNftExSku.getExStopTime());
                            if (now.isAfter(goblinNftExSku.getExStopTime()) && !gnc.getState().equals(2)) {
                                gnc.setState(3);
                            }
                            break;
                        }
                    }
                }
            }
        }

        PageInfoVo pageInfoVo = PageInfoVo.getNew();
        pageInfoVo.setList(goblinNftExCodeArrayList);
        pageInfoVo.setTotal(count);
        pageInfoVo.setSkuNumber(skuIdSet.size());
        return pageInfoVo;
    }

    @Override
    @Transactional
    public Boolean defDrivLoseCode(String codeIds) {
        // 获取兑换码
        List<GoblinNftExCode> goblinNftExCodes = goblinNftExCodeMapper.selectByIds(codeIds);
        for (GoblinNftExCode goblinNftExCode : goblinNftExCodes) {
            // redis 主动失效
            goblinNftExCode.setState(3);
            goblinNftExCode.setUpdatedAt(LocalDateTime.now());
            goblinRedisUtils.removeCode(goblinNftExCode.getCode());
        }
        // 批量修改
        goblinNftExCodeMapper.updateCodes(goblinNftExCodes);
        return true;
    }


    @Override
    @Transactional
    public ResponseDto<Boolean> addAirdrop(GoblinNftExCodeParam goblinNftExCodeParam) {
        String code = goblinNftExCodeParam.getCode();
        String phone = goblinNftExCodeParam.getPhone();

//        AdamUserInfoDto adamUserInfoDto = adamUserMapper.selectByPhone(phone);
//        if (adamUserInfoDto == null) {
//            return ResponseDto.failure("用户不存在!");
//        }
        // 根据兑换code查询兑换码信息
        GoblinNftExCode goblinNftExCode = goblinNftExCodeMapper.selectGoblinNftCodeByCode(code);
        if (goblinNftExCode == null) {
            return ResponseDto.failure("兑换码不存在!");
        }

        if (goblinNftExCode.getState().equals(2)) {
            return ResponseDto.failure("兑换码已领取!");
        }

        GoblinNftExCodeVo goblinNftExCodeVo = goblinRedisUtils.getGoblinNftExCodeVo(goblinNftExCode.getCode());
        if (goblinNftExCodeVo == null) {
            return ResponseDto.failure("兑换码已失效!");
        }

        if (goblinNftExCodeVo.getState().equals(2)) {
            return ResponseDto.failure("兑换码已领取!");
        }

        String uid = (String) redisDataSourceUtil.getRedisAdamUtil().get(AdamRedisConst.IDENTITY_MOBILE.concat(phone));
        if (StringUtils.isEmpty(uid)) {
            return ResponseDto.failure("用户不存在!");
        }

        // 验证吗时间校验
        try {
            MultiValueMap<String, String> params = new LinkedMultiValueMap();
            params.add("code", code);
//            params.add("userId", adamUserInfoDto.getUid());
            params.add("userId", uid);
            MultiValueMap<String, String> headers = CollectionUtil.linkedMultiValueMapStringString();
            headers.add("Accept", "application/json;charset=UTF-8");
            headers.add("Authorization", "Bearer " + CurrentUtil.getToken());
            String post = HttpUtil.post(orderUrl + "/order/goblin/nft/airdrop", params, headers);
            ResponseDto<Boolean> rsp = JsonUtils.fromJson(post, new TypeReference<ResponseDto<Boolean>>() {
            });
            if (rsp.isSuccess()) {
                goblinNftExCode.setAdminUid(goblinNftExCodeParam.getAdminUid());
                goblinNftExCodeMapper.updateCodeAdminUid(goblinNftExCode);
                return ResponseDto.success(true);
            } else {
                return ResponseDto.failure(rsp.getMessage());
            }
        } catch (Exception e) {
            // e.printStackTrace();
            return ResponseDto.failure("发送公投失败！");
        }
    }

    @Override
    public void excel(HttpServletResponse httpServletResponse, GoblinNftExCodeParam goblinNftExCodeParam) {

        // 入参
        GoblinNftExCode goblinNftExCode = GoblinNftExCode.getNew();
        goblinNftExCode.setCode(goblinNftExCodeParam.getCode());
        goblinNftExCode.setActivityId(goblinNftExCodeParam.getActivityId());
        goblinNftExCode.setState(goblinNftExCodeParam.getState());
        goblinNftExCode.setRedeemUid(goblinNftExCodeParam.getUserId());
        goblinNftExCode.setIsDrivi(goblinNftExCodeParam.getIsDrivi());
        if (StringUtil.isNotBlank(goblinNftExCodeParam.getSkuName())) {
            // 根据藏品名称获取 skuIds
            String skuName = goblinNftExCodeParam.getSkuName();
            List<GoblinGoodsSku> goblinGoodsSkus = goblinGoodsSkuMapper.selectSkuLikeName(skuName);
            if (goblinGoodsSkus.size() <= 0) {
                return;
            }
            StringBuffer skuIds = new StringBuffer();
            for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkus) {
                skuIds.append(goblinGoodsSku.getSkuId()).append(",");
            }
            goblinNftExCode.setSkuId(skuIds.deleteCharAt(skuIds.length() - 1).toString());
        }


        // PageHelper.startPage(goblinNftExCodeParam.getPageNum(), 20, true);
        List<GoblinNftExCode> goblinNftExCodes = goblinNftExCodeMapper.selectGoblinNftCodeExcel(goblinNftExCode);

        StringBuffer skuIds = new StringBuffer();
        StringBuffer acticityIds = new StringBuffer();
        for (GoblinNftExCode gnc : goblinNftExCodes) {
            skuIds.append(gnc.getSkuId()).append(",");
            if (StringUtil.isNotBlank(gnc.getBoxSkuId())) {
                skuIds.append(gnc.getBoxSkuId()).append(",");
            }
            acticityIds.append(gnc.getActivityId()).append(",");
        }

        // 获取返回对象实例
        ArrayList<GoblinNftExCodeVo> goblinNftExCodeArrayList = ObjectUtil.getGoblinNftExCodeVoArrayList();

        if (StringUtil.isNotBlank(skuIds)) {
            // 批量查询
            List<GoblinGoodsSku> goblinGoodsSkus = goblinGoodsSkuMapper.selectBySkuIds(skuIds.toString());
            for (GoblinNftExCode gnc : goblinNftExCodes) {
                GoblinNftExCodeVo goblinNftExCodeVo = GoblinNftExCodeVo.getNew().copy(gnc);
                for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkus) {
                    if (goblinNftExCodeVo.getSkuId().equals(goblinGoodsSku.getSkuId())) {
                        goblinNftExCodeVo.setSkuName(goblinGoodsSku.getName());
                    }

                    if (gnc.getState().equals(2)) {
                        if (StringUtil.isNotBlank(gnc.getBoxSkuId()) && gnc.getBoxSkuId().equals(goblinGoodsSku.getSkuId())) {
                            goblinNftExCodeVo.setResultSkuName(goblinGoodsSku.getName());
                        } else if (StringUtil.isBlank(gnc.getBoxSkuId()) && gnc.getSkuId().equals(goblinGoodsSku.getSkuId())) {
                            goblinNftExCodeVo.setResultSkuName(goblinGoodsSku.getName());
                        }
                    }
                }
                goblinNftExCodeArrayList.add(goblinNftExCodeVo);
            }
        }


        // 根据活动ids 获取兑换活动和sku的关联
        List<GoblinNftExSku> goblinNftExSkus = goblinNftExSkuMapper.selectGoblinNftExSkuByActivityIds(acticityIds.toString());

        ArrayList<CodeExcelVo> codeExcelVoArrayList = ObjectUtil.getCodeExcelVoArrayList();


        LocalDateTime now = LocalDateTime.now();
        for (GoblinNftExCodeVo gnc : goblinNftExCodeArrayList) {
            for (GoblinNftExSku goblinNftExSku : goblinNftExSkus) {
                if (gnc.getActivityId().equals(goblinNftExSku.getActivityId())) {
                    if (StringUtil.isNotBlank(gnc.getBoxSkuId()) && gnc.getSkuId().equals(goblinNftExSku.getSkuId())) {
                        gnc.setExStartTime(goblinNftExSku.getExStartTime());
                        gnc.setExStopTime(goblinNftExSku.getExStopTime());
                        if (now.isAfter(goblinNftExSku.getExStopTime())) {
                            gnc.setState(3);
                        }
                        break;
                    } else {
                        if (gnc.getSkuId().equals(goblinNftExSku.getSkuId())) {
                            gnc.setExStartTime(goblinNftExSku.getExStartTime());
                            gnc.setExStopTime(goblinNftExSku.getExStopTime());
                            if (now.isAfter(goblinNftExSku.getExStopTime())) {
                                gnc.setState(3);
                            }
                            break;
                        }
                    }
                }
            }


            CodeExcelVo codeExcelVo = CodeExcelVo.getNew();
            codeExcelVo.setCode(gnc.getCode());
            String val = "";
            switch (gnc.getState()) {
                case 1:
                    val = "未兑换";
                    break;
                case 2:
                    val = "已兑换";
                    break;
                case 3:
                    val = "已失效";
                    break;
                default:
                    val = "状态处理中";
            }
            codeExcelVo.setSkuName(gnc.getSkuName());
            codeExcelVo.setState(val);
            codeExcelVo.setExcelStartTime(gnc.getExStartTime().toString());
            codeExcelVo.setExcelStopTime(gnc.getExStopTime().toString());
            codeExcelVo.setRedeemUid(gnc.getRedeemUid());
            codeExcelVoArrayList.add(codeExcelVo);
        }


        try {
            writeExcel(httpServletResponse, codeExcelVoArrayList, "兑换码excel", "sheet1", CodeExcelVo.class);
        } catch (Exception e) {
            log.error("导出excel失败！");
        }

    }

    @Override
    public ResponseDto<Boolean> addAirdrops(MultipartFile file, String activityId, String adminUid) {

        // 手机号集合
        StringBuffer phonestr = new StringBuffer();
        List<String> phoneList = CollectionUtil.arrayListString();

        try {
            EasyExcel.read(file.getInputStream(), GoblinNftExCodeFetchExcelVo.class, new PageReadListener<GoblinNftExCodeFetchExcelVo>(dataList -> {
                for (GoblinNftExCodeFetchExcelVo data : dataList) {
                    if (data.getPhone() == null) {
                        continue;
                    }
                    phonestr.append(data.getPhone()).append(",");
                    phoneList.add(data.getPhone());
                    if(phoneList.size()>100){
                        break;
                    }
                }
            })).sheet().doRead();

        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure("解析文件失败！");
        }

        if(phoneList.size()>=100){
            return ResponseDto.failure("批量空投暂时数量不能大于100");
        }

        if (StringUtil.isNotBlank(phonestr)) {
            phonestr.deleteCharAt(phonestr.length() - 1);
        }

        // 根据手机号获取用户
        List<AdamUserInfoDto> adamUserInfoDtoList = adamUserMapper.selectByPhones(phonestr.toString());
        if (adamUserInfoDtoList == null || adamUserInfoDtoList.size() <= 0) {
            return ResponseDto.failure("根据手机号未能查询到用户！");
        }

        ArrayList<String> phoneCheckList = CollectionUtil.arrayListString();
        for (AdamUserInfoDto adamUserInfoDto : adamUserInfoDtoList) {
            phoneCheckList.add(adamUserInfoDto.getMobile());
        }

        // 根据活动id获取可用兑换码
        List<GoblinNftExCode> goblinNftExCodes = goblinNftExCodeMapper.selectCodeAvailableByActivityId(activityId);
        if (goblinNftExCodes.size() < phoneList.size()) {
            return ResponseDto.failure("可用兑换码数量不足!");
        }


        // 页条数
        int pageSize = 50;
        ArrayList<String> userIdList = CollectionUtil.arrayListString();
        StringBuffer userIds = new StringBuffer();
        StringBuffer phones = new StringBuffer();
        int pageNumber = 1;
        for (String phone : phoneList) {
            if (!phoneCheckList.contains(phone)) {
                log.error("mobile select not user :[{}]" + phone);
                continue;
            }


            AdamUserInfoDto adamUserInfo = null;
            for (AdamUserInfoDto adamUserInfoDto : adamUserInfoDtoList) {
                if (phone.equals(adamUserInfoDto.getMobile())) {
                    adamUserInfo = adamUserInfoDto;
                }
            }

            userIdList.add(adamUserInfo.getUid());
            userIds.append(adamUserInfo.getUid()).append(",");
            phones.append(adamUserInfo.getMobile()).append(",");
            if (userIdList.size() == pageSize) {
                StringBuffer codes = new StringBuffer();
                PageHelper.startPage(pageNumber, pageSize, true);
                List<GoblinNftExCode> goblinNftExCodeList = goblinNftExCodeMapper.selectCodeAvailableByActivityId(activityId);
                for (GoblinNftExCode goblinNftExCode : goblinNftExCodeList) {
                    codes.append(goblinNftExCode.getCode()).append(",");
                }
                HashMap<String, String> hashMap = CollectionUtil.mapStringString();
                codes.deleteCharAt(codes.length() - 1);
                userIds.deleteCharAt(userIds.length() - 1);
                hashMap.put("codes", codes.toString());
                hashMap.put("userIds", userIds.toString());
                hashMap.put("phones", phones.toString());
                hashMap.put("adminUid", adminUid);
                queueUtils.sendMssPhoneCodeRedis(hashMap);
                userIdList.clear();
                userIds = new StringBuffer();
                phones = new StringBuffer();
                pageNumber++;
            }
        }

        if (userIdList.size() > 0) {
            PageHelper.startPage(pageNumber, pageSize, true);
            List<GoblinNftExCode> goblinNftExCodeList = goblinNftExCodeMapper.selectCodeAvailableByActivityId(activityId);
            StringBuffer codes = new StringBuffer();
            for (GoblinNftExCode goblinNftExCode : goblinNftExCodeList) {
                codes.append(goblinNftExCode.getCode()).append(",");
            }
            HashMap<String, String> hashMap = CollectionUtil.mapStringString();
            codes.deleteCharAt(codes.length() - 1);
            userIds.deleteCharAt(userIds.length() - 1);
            hashMap.put("codes", codes.toString());
            hashMap.put("phones", phones.toString());
            hashMap.put("userIds", userIds.toString());
            hashMap.put("adminUid", adminUid);
            queueUtils.sendMssPhoneCodeRedis(hashMap);
            userIdList.clear();
        }

        return ResponseDto.success(true);
    }

    /**
     * 导出
     *
     * @param response
     * @param data
     * @param fileName
     * @param sheetName
     * @param clazz
     * @throws Exception
     */
    public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName,
                                  String sheetName, Class clazz) throws Exception {
        // 表头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy).doWrite(data);

    }

    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + "-" + LocalDate.now() + ".xlsx");
        return response.getOutputStream();
    }


}
