package com.xxfc.platform.activity.biz;

import cn.hutool.core.date.DateUtil;
import com.github.wxiaoqi.security.admin.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.util.excel.ExcelUtils;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.activity.bo.ActivityAttendanceRecordBo;
import com.xxfc.platform.activity.constant.PrizeTypeEnum;
import com.xxfc.platform.activity.dto.ActivityAttendanceRecordDTO;
import com.xxfc.platform.activity.dto.ActivityAttendanceRecordFindDTO;
import com.xxfc.platform.activity.entity.ActivityAttendanceRecord;
import com.xxfc.platform.activity.mapper.ActivityAttendanceRecordMapper;
import com.xxfc.platform.activity.vo.ActivityAttendanceRecordTotalVo;
import com.xxfc.platform.activity.vo.ActivityAttendanceRecordVo;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * 参与活动数据
 *
 * @author libin
 * @email 18178966185@163.com
 * @date 2019-12-04 14:54:06
 */
@Transactional(rollbackFor = Exception.class)
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ActivityAttendanceRecordBiz extends BaseBiz<ActivityAttendanceRecordMapper,ActivityAttendanceRecord> {
    @Resource(name = "redisTemplate")
    private ValueOperations<String, Object> valueOperations;

    private final RedisTemplate<String,Object> redisTemplate;

    @Value("${lottery.expire.days:60}")
    private int expirDays;

    public void attendActivity(Integer activityId, String activityName,AppUserDTO appUserDTO) {
        ActivityAttendanceRecord record = new ActivityAttendanceRecord();
        record.setActivityId(activityId);
        record.setUserId(appUserDTO.getUserid());
        int num = mapper.selectCount(record);
        if (num==0) {
            ActivityAttendanceRecord activityAttendanceRecord = new ActivityAttendanceRecord();
            activityAttendanceRecord.setActivityId(activityId);
            activityAttendanceRecord.setActivityName(activityName);
            activityAttendanceRecord.setUserId(appUserDTO.getUserid());
            activityAttendanceRecord.setPhone(appUserDTO.getUsername());
            activityAttendanceRecord.setUserName(StringUtils.isEmpty(appUserDTO.getRealname()) ? appUserDTO.getNickname() : appUserDTO.getRealname());
            activityAttendanceRecord.setPositionId(appUserDTO.getPositionId());
            activityAttendanceRecord.setPositionName(appUserDTO.getPositionName());
            activityAttendanceRecord.setCrtTime(new Date());
            mapper.insertSelective(activityAttendanceRecord);
            String onlineKey = String.format("%d:%d:%d", appUserDTO.getUserid(), activityId, PrizeTypeEnum.ONLINE.getCode());
            String localeKey = String.format("%d:%d:%d", appUserDTO.getUserid(), activityId, PrizeTypeEnum.LOCALE.getCode());
            redisTemplate.delete(Arrays.asList(onlineKey,localeKey));
            valueOperations.set(onlineKey, 1L,expirDays, TimeUnit.DAYS);
            valueOperations.set(localeKey, 1L,expirDays, TimeUnit.DAYS);
        }
    }


     public ActivityAttendanceRecordBo listActivityAttendanceRecord(ActivityAttendanceRecordFindDTO activityAttendanceRecordFindDTO){
         ActivityAttendanceRecordBo activityAttendanceRecordBo = new ActivityAttendanceRecordBo();
         PageDataVO<ActivityAttendanceRecordDTO> dataVO = PageDataVO.pageInfo(activityAttendanceRecordFindDTO.getPage(), activityAttendanceRecordFindDTO.getLimit(),
                 () -> mapper.selectActivityAttendanceRecord(activityAttendanceRecordFindDTO));
         List<ActivityAttendanceRecordDTO> data = dataVO.getData();
         if (CollectionUtils.isEmpty(data)){
             return activityAttendanceRecordBo;
         }
         ActivityAttendanceRecordTotalVo activityAttendanceRecordTotal = getActivityAttendanceRecordTotal(activityAttendanceRecordFindDTO);
         List<ActivityAttendanceRecordVo> activityAttendanceRecordVos = new ArrayList<>(data.size());
         ActivityAttendanceRecordVo activityAttendanceRecordVo = null;
         for (ActivityAttendanceRecordDTO attendanceRecordDTO : data) {
             activityAttendanceRecordVo = new ActivityAttendanceRecordVo();
             BeanUtils.copyProperties(attendanceRecordDTO,activityAttendanceRecordVo);
             activityAttendanceRecordVos.add(activityAttendanceRecordVo);
         }
         activityAttendanceRecordBo.setPageNum(dataVO.getPageNum());
         activityAttendanceRecordBo.setPageSize(dataVO.getPageSize());
         activityAttendanceRecordBo.setTotalPage(dataVO.getTotalPage());
         activityAttendanceRecordBo.setTotalCount(dataVO.getTotalCount());
         activityAttendanceRecordBo.setActivityAttendanceRecordVos(activityAttendanceRecordVos);
         activityAttendanceRecordBo.setActivityAttendanceRecordTotalVo(activityAttendanceRecordTotal);
         return activityAttendanceRecordBo;
     }

     private ActivityAttendanceRecordTotalVo getActivityAttendanceRecordTotal(ActivityAttendanceRecordFindDTO activityAttendanceRecordFindDTO){
         ActivityAttendanceRecordTotalVo activityAttendanceRecordTotalVo = new ActivityAttendanceRecordTotalVo();
         List<ActivityAttendanceRecordDTO> activityAttendanceRecordDTOS = mapper.selectActivityAttendanceRecord(activityAttendanceRecordFindDTO);
         if (CollectionUtils.isEmpty(activityAttendanceRecordDTOS)){
             return activityAttendanceRecordTotalVo;
         }
         activityAttendanceRecordTotalVo.setAttendNum(activityAttendanceRecordDTOS.size());
         Supplier<Stream<ActivityAttendanceRecordDTO>>  activityAttendanceRecordDTOStream = ()->activityAttendanceRecordDTOS.stream().filter(x->x.getStatus() == 1);
         activityAttendanceRecordTotalVo.setFinishNum(Long.valueOf(activityAttendanceRecordDTOStream.get().count()).intValue());
         activityAttendanceRecordTotalVo.setAmount(activityAttendanceRecordDTOStream.get().map(ActivityAttendanceRecordDTO::getAmount).reduce(BigDecimal.ZERO,BigDecimal::add));
         return activityAttendanceRecordTotalVo;
     }

    public Boolean hasNumberOfLuckyDrawByType(Integer activityId, Integer prizeType, Integer userid) {
        Object lotteryNum = valueOperations.get(String.format("%d:%d:%d", userid, activityId, prizeType));
        if (lotteryNum!=null){
            return  Integer.valueOf(lotteryNum.toString()) >0;
        }
        ActivityAttendanceRecord activityAttendanceRecord = new ActivityAttendanceRecord();
        activityAttendanceRecord.setActivityId(activityId);
        activityAttendanceRecord.setUserId(userid);
        activityAttendanceRecord = mapper.selectOne(activityAttendanceRecord);
        if (Objects.isNull(activityAttendanceRecord)){
            return false;
        }
        if (prizeType == PrizeTypeEnum.ONLINE.getCode()){
             valueOperations.set(String.format("%d:%d:%d", userid, activityId, prizeType),activityAttendanceRecord.getOnlineLotteryNum(),expirDays, TimeUnit.DAYS);
            return activityAttendanceRecord.getOnlineLotteryNum()>0;
        }
        if (prizeType ==PrizeTypeEnum.LOCALE.getCode()){
            valueOperations.set(String.format("%d:%d:%d", userid, activityId, prizeType),activityAttendanceRecord.getLocaleLotteryNum(),expirDays, TimeUnit.DAYS);
            return activityAttendanceRecord.getLocaleLotteryNum()>0;
        }
        return false;
    }

    public void exportActivityAttendanceRecordData(ActivityAttendanceRecordFindDTO activityAttendanceRecordFindDTO, ServletOutputStream outputStream) throws IOException {
        ExcelUtils excelUtils = new ExcelUtils("中奖列表");
        XSSFWorkbook hssfWorkbook = excelUtils.getHssfWorkbook();
        XSSFSheet sheet = excelUtils.getSheet();
        List<ActivityAttendanceRecordDTO> activityAttendanceRecordDTOS = mapper.selectActivityAttendanceRecord(activityAttendanceRecordFindDTO);
        ActivityAttendanceRecordTotalVo activityAttendanceRecordTotalVo = getActivityAttendanceRecordTotal(activityAttendanceRecordFindDTO);

        String[] header1 = {"参与人数","完成人数","已发放现金总额(元)"};
        Row headerRow1 = sheet.createRow(0);
        CellStyle headerCellStyle = excelUtils.createHeaderCellStyle();
        excelUtils.createHeader(headerRow1,0,header1,headerCellStyle);

        String[] headerValue = {activityAttendanceRecordTotalVo.getAttendNum().toString(),
                                activityAttendanceRecordTotalVo.getFinishNum().toString(),
                                activityAttendanceRecordTotalVo.getAmount().toString()};
        CellStyle generalCellStyle = excelUtils.createGeneralCellStyle();
        ArrayList<String[]> headerData = Lists.newArrayList();
        headerData.add(headerValue);
        excelUtils.createCellData(sheet,1,generalCellStyle,headerData);

        CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 0, 7);
        sheet.addMergedRegion(cellRangeAddress);

        String[] header2 = {"用户名","电话","身份","状态","当前金额(元)","邀请人数","抽奖礼品","参与时间"};
        Row header2Row = sheet.createRow(3);
        excelUtils.createHeader(header2Row,0,header2,headerCellStyle);

        List<String[]> activityAttendanceRecordList = getActivityAttendanceRecordDataList(activityAttendanceRecordDTOS);
        excelUtils.createCellData(sheet,4,generalCellStyle,activityAttendanceRecordList);

        hssfWorkbook.write(outputStream);
        hssfWorkbook.close();
    }


    public List<String[]> getActivityAttendanceRecordDataList(List<ActivityAttendanceRecordDTO> activityAttendanceRecordDTOS){
        List<String[]> activityAttendanceRecordDataList = new ArrayList<>(activityAttendanceRecordDTOS.size());
        for (ActivityAttendanceRecordDTO activityAttendanceRecordDTO : activityAttendanceRecordDTOS) {
            String[] activityAttendanceRecordData = getActivityAttendanceRecordData(activityAttendanceRecordDTO);
            activityAttendanceRecordDataList.add(activityAttendanceRecordData);
        }
        return activityAttendanceRecordDataList;
    }

    public String[] getActivityAttendanceRecordData(ActivityAttendanceRecordDTO activityAttendanceRecordDTO){
      String state= activityAttendanceRecordDTO.getStatus() == 1?"已完成":activityAttendanceRecordDTO.getStatus()==0?"进行中":"失败";
      String timeStr = DateUtil.format(new Date(activityAttendanceRecordDTO.getAttendTime()),"yyyy-MM-dd HH:mm:ss");
      return new String[]{activityAttendanceRecordDTO.getUserName(),
                          activityAttendanceRecordDTO.getPhone(),
      activityAttendanceRecordDTO.getPositionName(),
      state,
      activityAttendanceRecordDTO.getAmount()==null?BigDecimal.ZERO.toString():activityAttendanceRecordDTO.getAmount().toString(),
      activityAttendanceRecordDTO.getInviteNum()==null?"0":activityAttendanceRecordDTO.getInviteNum().toString(),
      activityAttendanceRecordDTO.getPrizes(),
      timeStr};
    }

    @Async
    public void updateLotteryNumByActivityIdAndUserIdAndPrizeType(Integer activityId,Integer userId,Integer prizeType){
         mapper.updateLotteryNumByActivityIdAndUserIdAndPrizeType(activityId,userId,prizeType);
    }
}