package com.ytpm.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ytpm.agent.model.YtApp;
import com.ytpm.agent.model.YtPlatformBanned;
import com.ytpm.agent.model.YtPlatformUserApp;
import com.ytpm.agent.view.AgentAdGroupStaticsVO;
import com.ytpm.agent.view.AgentTopCountView;
import com.ytpm.agent.view.AgentUserInfo;
import com.ytpm.app.model.YtDyzUser;
import com.ytpm.constant.StrConstant;
import com.ytpm.dao.AppMapper;
import com.ytpm.dao.RiskMapper;
import com.ytpm.general.RepMessage;
import com.ytpm.general.Result;
import com.ytpm.general.ResultTable;
import com.ytpm.middle.view.MessageVO;
import com.ytpm.service.AgentAppService;
import com.ytpm.service.YtAppUserService;
import com.ytpm.util.RedisService;
import com.ytpm.utils.FeignClientInvoker;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Api(tags = "首页数据统计模块")
@RestController
@Slf4j
@RequestMapping("/index")
public class AgentIndexController {
    @Resource
    private AgentAppService agentAppService;
    @Resource
    private AppMapper appMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private YtAppUserService appUserService;
    @Autowired
    private FeignClientInvoker feignInvoker;
    @Autowired
    private RiskMapper riskMapper;


    /**
     * 查询顶部数据展示
     */
    @ApiOperation("查询顶部数据展示")
    @GetMapping("/getTopCount")
    public Result<AgentTopCountView> getTopCount(@ApiIgnore @AuthenticationPrincipal AgentUserInfo userInfo){
        String key = StrConstant.TOP_COUNT+userInfo.getUserId();
        if(Boolean.TRUE.equals(redisService.hasKey(key))){
            String str = redisService.getStr(key);
            AgentTopCountView view = JSONObject.parseObject(str, AgentTopCountView.class);
            return Result.resultObjOk(view);
        }
        //查询用户所有应用
        ResultTable<YtPlatformUserApp> issuedAppList = agentAppService.getIssuedAppList(userInfo.getUserId());
        if(CollUtil.isEmpty(issuedAppList.getData())){
            return Result.resultErr(RepMessage.APP_EMPTY);
        }
        //查询广告数 查询用户数 查询预估收益 查询风控数
        int adCount = 0;
        int userCount = 0;
        int riskCount = 0;
        BigDecimal revenue = new BigDecimal(0);
        List<YtPlatformUserApp> appList = issuedAppList.getData();
        List<String> appIdList = agentAppService.getApkIdList(userInfo.getUserId());
        List<String> serveList = appList.stream().map(YtPlatformUserApp::getServiceName).distinct().collect(Collectors.toList());
        CountDownLatch countDownLatch = new CountDownLatch(serveList.size());
        for (String serve : serveList) {
            AgentTopCountView one = invokData(serve, appIdList,countDownLatch);
            adCount += one.getAdCount();
            userCount += one.getUserCount();
            riskCount += one.getRiskCount();
            revenue = revenue.add(one.getRevenue());
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        AgentTopCountView result = new AgentTopCountView(adCount,userCount,riskCount,revenue);
        redisService.setTimeOutMinutesStr(key,JSON.toJSONString(result),45);
        return Result.resultObjOk(result);
    }

    @Async
    AgentTopCountView invokData(String serve,List<String> appIdList,CountDownLatch countDownLatch) {
        Object o = feignInvoker.invoke(serve,"getAppTopCount", String.join(",", appIdList));
        String string = JSON.toJSONString(o);
        AgentTopCountView view = JSONObject.parseObject(string, AgentTopCountView.class);
        countDownLatch.countDown();
        return view;
    }

    /**
     * 查询广告平台收益
     */
    @ApiOperation("查询广告平台收益")
    @GetMapping("/profit")
    public Result<List<AgentAdGroupStaticsVO>> profit(@RequestParam(name = "appId")String appId,@ApiIgnore @AuthenticationPrincipal AgentUserInfo userInfo) {
        //校验应用状态
        YtPlatformUserApp app = agentAppService.selectByPrimaryKey(appId);
        if(Objects.isNull(app)){
            return Result.resultErr(RepMessage.OBJECT_NOT_EXIST);
        }
        List<YtApp> appList = appMapper.getBySuperiorId(appId);
        if(CollUtil.isEmpty(appList)){
            return Result.resultErr(RepMessage.APP_EMPTY);
        }
        //设定缓存键值
        String redisKey = StrConstant.PLATFORM_AGENT_SUFFIX + appId +StrConstant.PROFIT+userInfo.getUserId();
        String appIds = appList.stream().map(YtApp::getAppId).distinct().collect(Collectors.joining(","));
        //分广告平台，分别统计用户当天、昨日、本月的数据封装并返回
        if(Boolean.FALSE.equals(redisService.hasKey(redisKey))){
            Object o = feignInvoker.invoke(app.getServiceName(),"getAgentProfit", appIds);
            List<AgentAdGroupStaticsVO> agentProfit = JSONArray.parseArray(JSON.toJSONString(o), AgentAdGroupStaticsVO.class);
            if(CollUtil.isNotEmpty(agentProfit)){
                redisService.setTimeOutMinutesStr(redisKey, JSON.toJSONString(agentProfit),60);
            }
            return Result.resultObjOk(agentProfit);
        }
        //缓存取值
        String str = redisService.getStr(redisKey);
        List<AgentAdGroupStaticsVO> vos = JSONArray.parseArray(str, AgentAdGroupStaticsVO.class);
        return Result.resultObjOk(vos);
    }

    @ApiOperation("查询用户行为数据统计")
    @PostMapping("/userStatistic")
    public Result<Map<String, Object>> getDashboardData(@ApiIgnore @AuthenticationPrincipal AgentUserInfo userInfo) {
        String key = StrConstant.USER_STATISTIC+userInfo.getUserId();
        if(redisService.hasKey(key)){
            String str = redisService.getStr(key);
            Map<String, Object> map = JSON.parseObject(str, Map.class);
            return Result.resultObjOk(map);
        }
        Map<String, Object> result = new HashMap<>();
        //查询当前用户母包
        ResultTable<YtPlatformUserApp> issuedAppList = agentAppService.getIssuedAppList(userInfo.getUserId());
        if(CollUtil.isEmpty(issuedAppList.getData())){
            return Result.resultErr(RepMessage.APP_EMPTY);
        }
        List<String> appIdList = agentAppService.getApkIdList(userInfo.getUserId());
        List<YtPlatformUserApp> data = issuedAppList.getData();

        //查询 各APP 当月注册的所有用户
        List<YtDyzUser> allUserList = new ArrayList<>();
        List<YtDyzUser> allLoginList = new ArrayList<>();
        List<String> services = data.stream().map(YtPlatformUserApp::getServiceName).distinct().collect(Collectors.toList());
        for (String serve : services) {
            Object o = feignInvoker.invoke(serve,"getMonthRegistryUser", String.join(",", appIdList),1);
            List<YtDyzUser> dyzUsers = JSONArray.parseArray(JSON.toJSONString(o) , YtDyzUser.class);
            if(CollUtil.isNotEmpty(dyzUsers)){allUserList.addAll(dyzUsers);}

            o = feignInvoker.invoke(serve,"getMonthRegistryUser", String.join(",", appIdList),2);
            dyzUsers = JSONArray.parseArray(JSON.toJSONString(o) , YtDyzUser.class);
            if(CollUtil.isNotEmpty(dyzUsers)){allLoginList.addAll(dyzUsers);}
        }
        setRegistry(allUserList,result);
        setLogin(allLoginList,result);
        //设定封禁数
        int todayBannedCount,yestBannedCount,monthBannedCount;
        Map<String, Integer> bannedCountMap = new HashMap<>();
        List<YtPlatformBanned> banneds = riskMapper.queryMonthBanned(appIdList);
        if(CollUtil.isNotEmpty(banneds)){
            Date currentDate = new Date();
            List<YtPlatformBanned> collect = banneds.stream()
                    .filter(s -> DateUtil.isSameDay(s.getBannedTime(), currentDate))
                    .filter(item -> !"预估收益不到上限游客用户风控".equals(item.getBannedReason()))
                    .collect(Collectors.toList());
            if(CollUtil.isNotEmpty(collect)){
                SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Map<LocalDateTime, List<YtPlatformBanned>> bannedMap = collect.stream().collect(Collectors.groupingBy(
                        s -> DateUtil.parse(sf.format(s.getBannedTime()),"yyyy-MM-dd HH").toLocalDateTime()));
                for (Map.Entry<LocalDateTime, List<YtPlatformBanned>> entry : bannedMap.entrySet()) {
                    bannedCountMap.put(entry.getKey().toString(), entry.getValue().size());
                }
            }
        }
        result.put("todayLockHour", bannedCountMap);
        //查询指定封禁时间的用户
        todayBannedCount = riskMapper.queryBannedCount(appIdList,1);
        yestBannedCount = riskMapper.queryBannedCount(appIdList,2);
        monthBannedCount = riskMapper.queryBannedCount(appIdList,3);
        result.put("todayLock",todayBannedCount);
        result.put("yesterdayLock",yestBannedCount);
        result.put("monthLock",monthBannedCount);
        redisService.setTimeOutHoursStr(key,JSON.toJSONString(result),1);
        return Result.resultObjOk(result);

    }

    /**
     * 设置登录数
     */
    private void setLogin(List<YtDyzUser> allLoginList, Map<String, Object> result) {
        if(CollUtil.isEmpty(allLoginList))return;
        //设定注册数
        List<YtDyzUser> todayUserList = allLoginList.stream().filter(
                s -> DateUtil.isSameDay(s.getLastLoginTime(), new Date())).collect(Collectors.toList());
        int monthLogCount = allLoginList.size();
        int todayLogCount = todayUserList.size();
        Calendar cal = Calendar.getInstance(); // 获取当前日期时间
        cal.add(Calendar.DATE, -1); // 昨天的日期时间
        Date date = cal.getTime();
        int yestLogCount = Math.toIntExact(allLoginList.stream().filter(
                s -> DateUtil.isSameDay(s.getLastLoginTime(), date)).count());
        result.put("todayLogin",todayLogCount);
        result.put("yesterdayLogin",yestLogCount);
        result.put("monthLogin",monthLogCount);
    }

    /**
     * 设置注册数
     */
    private void setRegistry(List<YtDyzUser> allUserList, Map<String, Object> result) {
        if(CollUtil.isEmpty(allUserList))return;
        //设定注册数
        List<YtDyzUser> todayUserList = allUserList.stream().filter(
                s -> DateUtil.isSameDay(s.getRegistryTime(), new Date())).collect(Collectors.toList());
        int monthRegCount = allUserList.size();
        int todayRegCount = todayUserList.size();
        Calendar cal = Calendar.getInstance(); // 获取当前日期时间
        cal.add(Calendar.DATE, -1); // 昨天的日期时间
        Date date = cal.getTime();
        int yestRegCount = Math.toIntExact(allUserList.stream().filter(
                s -> DateUtil.isSameDay(s.getRegistryTime(), date)).count());
        result.put("today",todayRegCount);
        result.put("yesterday",yestRegCount);
        result.put("month",monthRegCount);
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(CollUtil.isNotEmpty(todayUserList)){
            Map<LocalDateTime, List<YtDyzUser>> registryMap = todayUserList.stream()
                    .collect(Collectors.groupingBy(
                            s -> DateUtil.parse(sf.format(s.getRegistryTime()),"yyyy-MM-dd HH").toLocalDateTime()));
            Map<String, Integer> registryCountMap = new HashMap<>();
            for (Map.Entry<LocalDateTime, List<YtDyzUser>> entry : registryMap.entrySet()) {
                registryCountMap.put(entry.getKey().toString(), entry.getValue().size());
            }
            result.put("todayUser",registryCountMap);
        }
    }

    @ApiOperation("查询我的未读通知")
    @GetMapping("/unreadMessage")
    public ResultTable<MessageVO> unreadMessage(@ApiIgnore @AuthenticationPrincipal AgentUserInfo userInfo) {
        return appUserService.unreadMessage(userInfo.getUserId());
    }

    @ApiImplicitParam(name = "messageId", value = "消息ID")
    @ApiOperation("标记为已读")
    @GetMapping("/markRead")
    public Result<String> markRead(@RequestParam(name = "messageId")String messageId, @ApiIgnore @AuthenticationPrincipal AgentUserInfo userInfo) {
        return appUserService.markRead(messageId,userInfo.getUserId());
    }

}
