package org.jeecg.ctop.material.controller;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.DateUtils;
import org.jeecg.ctop.material.service.IAdqAdvertiserReportService;
import org.jeecg.ctop.material.service.IBytedanceAccountReportDailyDwService;
import org.jeecg.ctop.material.service.IKuaishouAccountReportDailyDwService;
import org.jeecg.ctop.material.service.support.DashboardLocalCacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

/**
 * 汇总数据
 */
@RestController
@RequestMapping("summary/report")
@Slf4j
public class ReportController {

    private static final long REALTIME_CACHE_TTL = 30 * 1000L;
    private static final long HISTORY_CACHE_TTL = 5 * 60 * 1000L;

    @Autowired
    private IKuaishouAccountReportDailyDwService kuaishouReportService;

    @Resource
    private IBytedanceAccountReportDailyDwService bytedanceReportService;

    @Resource
    private IAdqAdvertiserReportService adqAdvertiserReportService;

    @Resource
    private DashboardLocalCacheService dashboardLocalCacheService;

    @Resource(name = "dashboardSummaryExecutor")
    private Executor dashboardSummaryExecutor;


    /**
     * 获取快手&&头条当日消耗、自然周同比、日环比
     */
    @GetMapping("/getTotalCharge")
    public Result<Object> getTotalCharge() {
        try {
            String today = DateUtils.formatDate(new Date());
            Integer nowHour = DateUtils.getNowHour();
            String cacheKey = "dashboard:summary:getTotalCharge:" + today + ":" + nowHour;
            return getCachedResult(cacheKey, REALTIME_CACHE_TTL, () -> loadTotalCharge(today, nowHour));
        } catch (Exception e) {
            log.error("getTotalCharge error", e);
        }
        return Result.error("查询失败");
    }

    private Result<Object> loadTotalCharge(String today, Integer nowHour) {
        log.info("----------------开始请求-----------------");
        try {
            //本周一
            String monday = DateUtils.getdateFromWeek(1);
            //昨天日期
            String yesterday = DateUtils.getLastDay(today, 1);
            //上周一日期
            String lastStartDate = DateUtils.getLastDay(monday, 7);
            //上周当天日期
            String lastEndDate = DateUtils.getLastDay(today, 7);
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("lastStartDate", DateUtils.getDateInteger(lastStartDate));
            paramsMap.put("lastEndDate", DateUtils.getDateInteger(lastEndDate));
            paramsMap.put("monday", DateUtils.getDateInteger(monday));
            paramsMap.put("today", DateUtils.getDateInteger(today));
            paramsMap.put("yesterday", DateUtils.getDateInteger(yesterday));
            paramsMap.put("hour", nowHour);

            CompletableFuture<JSONObject> kuaishouFuture = querySummaryAsync(
                    "kuaishou",
                    () -> kuaishouReportService.getTotalCharge(Collections.unmodifiableMap(new HashMap<>(paramsMap)))
            );
            CompletableFuture<JSONObject> bytedanceFuture = querySummaryAsync(
                    "bytedance",
                    () -> bytedanceReportService.getTotalCharge(Collections.unmodifiableMap(new HashMap<>(paramsMap)))
            );
            CompletableFuture<JSONObject> tencentFuture = querySummaryAsync(
                    "tencent",
                    () -> adqAdvertiserReportService.getTotalCharge(Collections.unmodifiableMap(new HashMap<>(paramsMap)))
            );
            CompletableFuture.allOf(kuaishouFuture, bytedanceFuture, tencentFuture).join();
            JSONObject kuaishou = kuaishouFuture.join();
            JSONObject bytedance = bytedanceFuture.join();
            JSONObject tencent = tencentFuture.join();
            JSONObject data = new JSONObject();
            data.put("kuaishou", kuaishou);
            data.put("bytedance", bytedance);
            data.put("tencent", tencent);
            log.info("----------------请求结束-----------------");
            return Result.OK(data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private CompletableFuture<JSONObject> querySummaryAsync(String media, Supplier<JSONObject> supplier) {
        return CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            try {
                return supplier.get();
            } finally {
                log.info("getTotalCharge {} finished in {} ms", media, System.currentTimeMillis() - start);
            }
        }, dashboardSummaryExecutor);
    }


    /**
     * 项目数据折线趋势图
     *
     * @param endTime
     * @param startTime
     * @param mediaId
     */
    @GetMapping("/getTrendCharge")
    public Result<Object> getTrendCharge(String type, String mediaId, Long projectId, String startTime, String endTime) {
        try {
            String cacheKey = "dashboard:summary:getTrendCharge:" + safe(mediaId) + ":" + safe(type) + ":" + safe(projectId) + ":" + safe(startTime) + ":" + safe(endTime);
            return getCachedResult(cacheKey, resolveCacheTtl(startTime, endTime), () -> {
                JSONObject data;
                if ("1".equals(mediaId)) {
                    data = bytedanceReportService.getTrendCharge(type, projectId, startTime, endTime);
                } else if ("16".equals(mediaId)) {
                    data = adqAdvertiserReportService.getTrendCharge(type, projectId, startTime, endTime);
                } else {
                    data = kuaishouReportService.getTrendCharge(type, projectId, startTime, endTime);
                }
                return Result.OK(data);
            });
        } catch (Exception e) {
            log.error("getTrendCharge error", e);
        }
        return Result.error("查询失败");
    }

    /**
     * 获取项目报表
     *
     * @param endTime
     * @param startTime
     * @param mediaId
     */
    @GetMapping("/getProjectReport")
    public Result<Object> getProjectReport(String mediaId, String category, String sortCode, String order, Long projectId, String startTime, String endTime, String userId, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "allData", defaultValue = "false") Boolean allData) {
        try {
            String cacheKey = "dashboard:summary:getProjectReport:" + safe(mediaId) + ":" + safe(category) + ":" + safe(sortCode) + ":" + safe(order) + ":" + safe(projectId) + ":" + safe(startTime) + ":" + safe(endTime) + ":" + safe(userId) + ":" + safe(pageNo) + ":" + safe(pageSize) + ":" + safe(allData);
            return getCachedResult(cacheKey, resolveCacheTtl(startTime, endTime), () -> {
                try {
                    if ("1".equals(mediaId)) {
                        return bytedanceReportService.getProjectReport(category, projectId, startTime, endTime, sortCode, order, pageSize, pageNo, allData);
                    } else if ("16".equals(mediaId)) {
                        return adqAdvertiserReportService.getProjectReport(category, projectId, startTime, endTime, sortCode, order, pageSize, pageNo, userId, allData);
                    }
                    return kuaishouReportService.getProjectReport(category, projectId, startTime, endTime, sortCode, order, pageSize, pageNo, allData);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            log.error("getProjectReport error", e);
        }
        return Result.error("查询失败");
    }

    /**
     * 获取运营数据
     *
     * @param endTime
     * @param startTime
     * @param mediaId
     */
    @GetMapping("/getOperateInfo")
    public Result<Object> getOperateInfo(String mediaId, String category, String sortCode, String order, String startTime, String endTime, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        try {
            String cacheKey = "dashboard:summary:getOperateInfo:" + safe(mediaId) + ":" + safe(startTime) + ":" + safe(endTime);
            return getCachedResult(cacheKey, resolveCacheTtl(startTime, endTime), () -> {
                if ("1".equals(mediaId)) {
                    return bytedanceReportService.getOperateInfo(startTime, endTime);
                } else if ("16".equals(mediaId)) {
                    return adqAdvertiserReportService.getOperateInfo(startTime, endTime);
                }
                return kuaishouReportService.getOperateInfo(startTime, endTime);
            });
        } catch (Exception e) {
            log.error("getOperateInfo error", e);
        }
        return Result.error("查询失败");
    }


    /**
     * 获取运营组数据
     *
     * @param endTime
     * @param startTime
     * @param mediaId
     */
    @GetMapping("/getOperateGroupInfo")
    public Result<Object> getOperateGroupInfo(String mediaId, String startTime, String endTime) {
        try {
            String cacheKey = "dashboard:summary:getOperateGroupInfo:" + safe(mediaId) + ":" + safe(startTime) + ":" + safe(endTime);
            return getCachedResult(cacheKey, resolveCacheTtl(startTime, endTime), () -> {
                if ("1".equals(mediaId)) {
                    return bytedanceReportService.getOperateGroupInfo(startTime, endTime);
                } else if ("16".equals(mediaId)) {
                    return adqAdvertiserReportService.getOperateGroupInfo(startTime, endTime);
                }
                return kuaishouReportService.getOperateGroupInfo(startTime, endTime);
            });
        } catch (Exception e) {
            log.error("getOperateGroupInfo error", e);
        }
        return Result.error("查询失败");
    }

    private Result<Object> getCachedResult(String cacheKey, long ttlMillis, Supplier<Result<Object>> loader) {
        return dashboardLocalCacheService.getIfCacheable(cacheKey, ttlMillis, loader, result -> result != null && result.isSuccess());
    }

    private long resolveCacheTtl(String startTime, String endTime) {
        String today = DateUtils.formatDate(new Date());
        if (today.equals(startTime) && today.equals(endTime)) {
            return REALTIME_CACHE_TTL;
        }
        return HISTORY_CACHE_TTL;
    }

    private String safe(Object value) {
        return value == null ? "null" : String.valueOf(value);
    }

}
