package com.izouma.nineth.aspect;

import com.izouma.nineth.domain.Asset;
import com.izouma.nineth.service.UserAssetSummaryService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class AssetSaveAspect {

    private final UserAssetSummaryService  userAssetSummaryService;
    private final ScheduledExecutorService executorService;
    private final Map<Long, Future>        futureMap;

    public AssetSaveAspect(UserAssetSummaryService userAssetSummaryService, ScheduledExecutorService executorService) {
        this.userAssetSummaryService = userAssetSummaryService;
        this.executorService = executorService;
        this.futureMap = new HashMap<>();
    }

    @After("execution(* com.izouma.nineth.repo.AssetRepo.save(..)) || execution(* com.izouma.nineth.repo.AssetRepo.saveAndFlush(..))")
    public void redisLock(JoinPoint joinPoint) {
        log.info("enter AssetSaveAspect");
        try {
            Asset asset = (Asset) joinPoint.getArgs()[0];
            log.info("recalculate user asset summary {}", asset.getUserId());
            synchronized (AssetSaveAspect.class) {
                Optional.ofNullable(futureMap.get(asset.getUserId()))
                        .ifPresent(f -> {
                            log.info("debouncing previous task {}", asset.getUserId());
                            f.cancel(false);
                        });
                futureMap.put(asset.getUserId(), executorService.schedule(() -> {
                    userAssetSummaryService.calculateNum(asset.getUserId());
                }, 500, TimeUnit.MILLISECONDS));
            }
        } catch (Exception e) {
            log.error("AssetSaveAspect error", e);
        }
    }
}