package com.izouma.nineth.service;

import com.izouma.nineth.annotations.Debounce;
import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.domain.Collection;
import com.izouma.nineth.domain.MintActivity;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.repo.MintActivityRepo;
import com.izouma.nineth.utils.JpaUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@AllArgsConstructor
public class MintActivityService {

    private       MintActivityRepo              mintActivityRepo;
    private       RedisTemplate<String, Object> redisTemplate;
    private       CacheService                  cacheService;
    private       RocketMQTemplate              rocketMQTemplate;
    private       GeneralProperties             generalProperties;
    private       TaskScheduler                 taskScheduler;
    private final Map<Long, ScheduledFuture<?>> tasks = new HashMap<>();


    public Page<MintActivity> all(PageQuery pageQuery) {
        return mintActivityRepo.findAll(JpaUtils.toSpecification(pageQuery, MintActivity.class), JpaUtils.toPageRequest(pageQuery));
    }

    public synchronized Long increaseStock(Long id, int number) {
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.MINT_ACTIVITY_STOCK + id);
        if (ops.get() == null) {
            Boolean success = ops.setIfAbsent(Optional.ofNullable(mintActivityRepo.getStock(id))
                    .orElse(0), 7, TimeUnit.DAYS);
            log.info("创建redis铸造活动库存：{}", success);
        }
        Long stock = ops.increment(number);
        rocketMQTemplate.convertAndSend(generalProperties.getUpdateActivityStockTopic(), id);
        return stock;
    }

    public synchronized Long decreaseStock(Long id, int number) {
        return increaseStock(id, -number);
    }

/*    public synchronized Long increaseSale(Long id, int number) {
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps("mintActivitySale::" + id);
        if (ops.get() == null) {
            Boolean success = ops.setIfAbsent(Optional.ofNullable(mintActivityRepo.getStock(id))
                    .orElse(0), 7, TimeUnit.DAYS);
            log.info("创建redis铸造活动销量：{}", success);
        }
        Long sale = ops.increment(number);
        return sale;
    }

    public synchronized Long decreaseSale(Long id, int number) {
        return increaseSale(id, -number);
    }*/

    @Debounce(key = "#id", delay = 500)
    public void syncStock(Long id) {
        Integer stock = (Integer) redisTemplate.opsForValue().get(RedisKeys.MINT_ACTIVITY_STOCK + id);
        if (stock != null) {
            log.info("同步铸造活动库存信息{}", id);
            mintActivityRepo.updateStock(id, stock);
            cacheService.clearMintActivity(id);
        }
    }

    private void onShelfTask(MintActivity record) {
        ScheduledFuture<?> task = tasks.get(record.getId());
        if (task != null) {
            if (!task.cancel(true)) {
                return;
            }
        }
        if (record.isScheduleSale()) {
            if (record.getStartTime().minusSeconds(2).isAfter(LocalDateTime.now())) {
                Date date = Date.from(record.getStartTime().atZone(ZoneId.systemDefault()).toInstant());
                ScheduledFuture<?> future = taskScheduler.schedule(() -> {
                    mintActivityRepo.scheduleOnShelf(record.getId());
                    tasks.remove(record.getId());
                }, date);
                tasks.put(record.getId(), future);
            } else {
                mintActivityRepo.scheduleOnShelf(record.getId());
            }
        }
    }

}
