package io.renren.application.common.service.imp;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.application.common.dto.ChaoXiangParamDto;
import io.renren.application.common.dto.ChaoXiangTimeDto;
import io.renren.application.common.entity.SysPublicParam;
import io.renren.application.common.mapper.SysPublicParamMapper;
import io.renren.application.common.service.SysPublicParamService;
import io.renren.application.common.util.ChaoXiangUtils;
import io.renren.application.common.vo.ChaoXiangParamVo;
import io.renren.application.common.vo.Results;
import io.renren.common.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
@Component
@EnableScheduling
public class SysPublicParamServiceImpl extends ServiceImpl<SysPublicParamMapper, SysPublicParam> implements SysPublicParamService {
    final RedisTemplate<String,Object> redisTemplate;
    final RedisUtils redisUtils;
    String CHAO_XIANG_STOCK_KEY = "CHAO_XIANG_STOCK_KEY";
    String CHAO_XIANG_PARAM_PRE = "CHAO_XIANG_PARAM_QRCODE_WEEK_";
    String CHAO_XIANG_ADS_TIME_KEY = "CHAO_XIANG_ADS_TIME";
    String CHAO_XIANG_ADS_END_TIME = "CHAO_XIANG_ADS_END_TIME";
    String LOCK = CHAO_XIANG_STOCK_KEY+":lock";
    @Override
    public Results modeifyParam(ChaoXiangParamDto dto) {
        if (dto.getValues()==null){
            dto.setValues(new ArrayList<>(7));//初始化
        }
        Integer size = 7;
        while (dto.getValues().size()<7){
            dto.getValues().add("");//补全
        }
        for (int i = 0; i <size ; i++) {
            String value = dto.getValues().get(i);
            String key = CHAO_XIANG_PARAM_PRE+(i+1);
            SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,key));
            if (publicParam==null){
                publicParam = new SysPublicParam();
                publicParam.setPublicKey(key);
            }
            publicParam.setPublicValue(value);
            publicParam.setStatus(1);
            publicParam.insertOrUpdate();
        }
        return Results.success();
    }

    @Override
    public Results<ChaoXiangParamVo> getAllWeekParam() {
        List<ChaoXiangParamVo> list = new ArrayList<>();
        for (int i = 1; i <= 7; i++) {
            ChaoXiangParamVo vo = new ChaoXiangParamVo();
            String name = DayOfWeek.of(i).name();
            String value = null;
            SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_PARAM_PRE+i));
            if (publicParam !=null){
                value = publicParam.getPublicValue();
            }
            vo.setName(name);
            vo.setValue(value);
            list.add(vo);
        }
        return Results.success(list);
    }

    @Override
    public Results<String> getWeekParam() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = now.plusDays(1).withHour(0).withMinute(0).withSecond(0).plusNanos(-1);
        SysPublicParam startParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_PARAM_PRE+"START"));
        Integer hour = 20;
        Integer min = 0;
        Integer second = 0;
        if (startParam !=null&&startParam.getPublicValue()!=null){
            String[] params = startParam.getPublicValue().split(":");
            if (params.length>0){
                hour = Integer.valueOf(params[0]);
            }
            if (params.length>1){
                min = Integer.valueOf(params[1]);
            }
            if (params.length>2){
                second = Integer.valueOf(params[2]);
            }
        }else{
            startParam = new SysPublicParam();
            startParam.setPublicValue(hour+":0"+min+":0"+second);
        }
        StringBuffer sb = new StringBuffer();
        sb.append("活动");
        if (hour<10){
            sb.append("0");
        }
        sb.append(hour+"点");
        if (min>0&&min<10){
            sb.append("0"+min+"分");
        }else if (min>0&&min>=10){
            sb.append(min+"分");
        }
        sb.append("准时开启");
        LocalDateTime start = now.withHour(hour).withMinute(min).withSecond(second).withNano(0);
        if (now.isBefore(end)&&now.isAfter(start)){
            int i = LocalDateTime.now().getDayOfWeek().getValue();
            SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_PARAM_PRE+i));
            if (publicParam ==null){
                return Results.success();
            }
            //todo 减库存
            changeStock(getCacheStock()-1);
            return Results.success(publicParam.getPublicValue());
        }else{
            return Results.error(10,sb.toString());
        }

    }

    @Override
    public Results<Integer> getAdsTime() {
        SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_ADS_TIME_KEY));
        if (publicParam ==null){
            return Results.success();
        }
        return Results.success(Integer.valueOf(publicParam.getPublicValue()));
    }

    @Override
    public Results modifyAdsTime(ChaoXiangTimeDto dto) {
        if (dto.getTime()==null||dto.getTime()<0){
            return Results.error("请正确填写毫秒数");
        }
        SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_ADS_TIME_KEY));
        if (publicParam==null){
            publicParam = new SysPublicParam();
            publicParam.setPublicKey(CHAO_XIANG_ADS_TIME_KEY);
        }
        publicParam.setPublicValue(dto.getTime().toString());
        publicParam.setStatus(1);
        publicParam.insertOrUpdate();
        return Results.success();
    }

    @Override
    public Results hasStock(Integer checkTime) {
        Long start = System.currentTimeMillis();
        try {


        SysPublicParam publicParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_ADS_END_TIME));
        String time = "20:05:00";
        if (publicParam!=null&&StringUtils.isNotBlank(publicParam.getPublicValue())){
            time = publicParam.getPublicValue();
        }
        LocalDateTime today = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String endTimeStr = today.format(formatter)+" "+time;
        DateTimeFormatter endFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime endTime = LocalDateTime.parse(endTimeStr,endFormatter);
        int i = LocalDateTime.now().getDayOfWeek().getValue();
        SysPublicParam idParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_PARAM_PRE+i));
        String id = null;
        if (Integer.valueOf(1).equals(checkTime)){
            id = getWeekParam().getData();
        }else{
            if (idParam !=null){
                id = idParam.getPublicValue();
            }
        }

        try {
            Integer stock = getCacheStock();
            if (stock!=null&&stock>0){
                if (today.isAfter(endTime)){
                    log.info("超出限制时间，不再强制要求观看广告");
                    return Results.success(0);
                }
                return Results.success(stock);
            }
        } catch (Exception e) {
            return Results.success(-1);
        }
        return Results.success(-1);
        }finally {
            Long end = System.currentTimeMillis();
            log.info("用户端查询库存耗时:{}ms",end-start);
        }
    }

    Integer getCacheStock(){
        Object value = redisTemplate.opsForValue().get(CHAO_XIANG_STOCK_KEY);
        if (value!=null&&value.toString().matches("\\d+")){
            return Integer.valueOf(value.toString());
        }
        log.info("缓存库存：{}",Integer.valueOf(value.toString()));
        return 0;
    }

    synchronized void changeStock(Integer value){
        redisTemplate.opsForValue().set(CHAO_XIANG_STOCK_KEY,value.toString());
    }

    @Scheduled(cron = "0 0/1 * * * ? ")
    public void synStock() throws IOException {
        int i = LocalDateTime.now().getDayOfWeek().getValue();
        SysPublicParam idParam = getOne(Wrappers.<SysPublicParam>lambdaQuery().eq(SysPublicParam::getPublicKey,CHAO_XIANG_PARAM_PRE+i));
        String id = null;
        if (idParam !=null){
            id = idParam.getPublicValue();
        }
        log.info("开始查询库存 id:{}",id);
        Integer stock = ChaoXiangUtils.getStock(id);
        changeStock(stock);
    }

    @Scheduled(cron = "0 0/10 * * * ? ")
    public void checkToken() {
        Boolean fail = true;
        for (int i = 1; i <= 10 && fail; i++){
            try {
                String token = ChaoXiangUtils.login();
                if (StringUtils.isNotBlank(token)) {
                    log.info("超翔令牌获取成功.");
                    fail = false;
                } else {
                    log.warn("超翔令牌获取失败.");
                    fail = true;
                }
            } catch (Exception e) {
                log.error("第{}次获取超翔令牌失败",i,e);
            }
        }
    }

}
