package com.ruoyi.ibs.dashboard.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.ibs.dashboard.domain.entity.DashboardQuickAccess;
import com.ruoyi.ibs.dashboard.domain.entity.LoadIndDmPaItemHome;
import com.ruoyi.ibs.dashboard.domain.entity.LoanContractDueWarn;
import com.ruoyi.ibs.dashboard.domain.entity.UrlRegistry;
import com.ruoyi.ibs.dashboard.domain.vo.CommonRespVO;
import com.ruoyi.ibs.dashboard.domain.vo.LoanContractDueWarnVO;
import com.ruoyi.ibs.dashboard.domain.vo.WarnInfoVO;
import com.ruoyi.ibs.dashboard.mapper.DashboardQuickAccessMapper;
import com.ruoyi.ibs.dashboard.mapper.LoadIndDmPaItemHomeMapper;
import com.ruoyi.ibs.dashboard.mapper.LoanContractDueWarnMapper;
import com.ruoyi.ibs.dashboard.mapper.UrlRegistryMapper;
import com.ruoyi.ibs.dashboard.service.DashboardService;
import com.ruoyi.system.service.ISysMenuService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author 吴凯程
 * @Date 2025/3/7
 **/
@Service
public class DashboardServiceImpl implements DashboardService {

    private static final Logger log = LoggerFactory.getLogger(DashboardServiceImpl.class);

    @Resource
    private LoanContractDueWarnMapper loanContractDueWarnMapper;

    @Resource
    private DashboardQuickAccessMapper dashboardQuickAccessMapper;

    @Resource
    private ISysMenuService menuService;

    @Resource
    private LoadIndDmPaItemHomeMapper loadIndDmPaItemHomeMapper;

    @Resource
    private UrlRegistryMapper urlRegistryMapper;

    @Resource
    private RedisCache redisCache;

    public static final String REDIS_KEY_TOKEN = "api_token:";


    /**
     * @return
     */
    @Override
    public List<LoanContractDueWarnVO> getLoanWarnList() {
        LambdaQueryWrapper<LoanContractDueWarn> queryWrapper = new LambdaQueryWrapper<>();
        if (SecurityUtils.isHead() || SecurityUtils.hasRole("headAdmin")){
            queryWrapper.likeRight(LoanContractDueWarn::getBranchCode,SecurityUtils.getHeadId());
        }else{
            if (SecurityUtils.hasRole("branchAdmin")){
                queryWrapper.eq(LoanContractDueWarn::getBranchCode,SecurityUtils.getDeptId());
            }else if (SecurityUtils.hasRole("outletAdmin")){
                queryWrapper.eq(LoanContractDueWarn::getOutletCode,SecurityUtils.getDeptId());
            }else{
                queryWrapper.eq(LoanContractDueWarn::getBelongManager,SecurityUtils.getUsername());
            }
        }
        queryWrapper.orderByAsc(LoanContractDueWarn::getLoanDueWarnValue);
        List<LoanContractDueWarnVO> collect = loanContractDueWarnMapper.selectList(queryWrapper).stream().map(loanContractDueWarn -> {
            LoanContractDueWarnVO loanContractDueWarnVO = new LoanContractDueWarnVO();
            BeanUtils.copyProperties(loanContractDueWarn, loanContractDueWarnVO);
            return loanContractDueWarnVO;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * @return
     */
    @Override
    public List<WarnInfoVO> getWarnInfoList() {
        List<UrlRegistry> urlRegistries = urlRegistryMapper.selectUrlList(SecurityUtils.getHeadId(), "1");
        if (!urlRegistries.isEmpty()) {
            List<WarnInfoVO> warnInfoVOList = urlRegistries.stream().map(urlRegistry -> {
                String urlName = urlRegistry.getUrlName();
                WarnInfoVO warnInfoVO = new WarnInfoVO();
                warnInfoVO.setInfoName(urlName);
                warnInfoVO.setInfoCount(getWarnRespList(urlName, 1L, 10L).getTotal());
//                warnInfoVO.setInfoCount(0L); //测试
                return warnInfoVO;
            }).collect(Collectors.toList());
            return warnInfoVOList;
        }else {
            List<WarnInfoVO> warnInfoVOList = new ArrayList<>();
            WarnInfoVO warnInfoVO = new WarnInfoVO();
            warnInfoVO.setInfoName("贷款合同到期提醒");
            warnInfoVO.setInfoCount(getLoanWarnCount());
            warnInfoVOList.add(warnInfoVO);
            return warnInfoVOList;
        }
    }

    @Override
    public Long getLoanWarnCount() {
        LambdaQueryWrapper<LoanContractDueWarn> queryWrapper = new LambdaQueryWrapper<>();
        if (SecurityUtils.isHead() || SecurityUtils.hasRole("headAdmin")){
            queryWrapper.likeRight(LoanContractDueWarn::getBranchCode,SecurityUtils.getHeadId());
            if (SecurityUtils.hasRole("headPrivate")){
                queryWrapper.and(i -> i.eq(LoanContractDueWarn::getCustType,"0").or().eq(LoanContractDueWarn::getCustType,"1"));
            }else if (SecurityUtils.hasRole("headPublic")){
                queryWrapper.eq(LoanContractDueWarn::getCustType,"2");
            }
        }else{
            if (SecurityUtils.hasRole("branchAdmin")){
                queryWrapper.eq(LoanContractDueWarn::getBranchCode,SecurityUtils.getDeptId());
            }else if (SecurityUtils.hasRole("outletAdmin")){
                queryWrapper.eq(LoanContractDueWarn::getOutletCode,SecurityUtils.getDeptId());
            }else{
                queryWrapper.eq(LoanContractDueWarn::getBelongManager,SecurityUtils.getUsername());
            }
        }
        return loanContractDueWarnMapper.selectCount(queryWrapper);
    }

    /**
     * @param routeNames
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateQuickAccess(List<String> routeNames) {
        LambdaQueryWrapper<DashboardQuickAccess> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(DashboardQuickAccess::getCreateBy, SecurityUtils.getUsername());
        dashboardQuickAccessMapper.delete(queryWrapper);
        for (int i = 0; i < routeNames.size(); i++) {
            DashboardQuickAccess dashboardQuickAccess = new DashboardQuickAccess();
            dashboardQuickAccess.setTitle(routeNames.get(i));
            dashboardQuickAccess.setTitleOrder(i);
            dashboardQuickAccessMapper.insert(dashboardQuickAccess);
        }

        return "快速访问设置完成";
    }

    /**
     * @return
     */
    @Override
    public List<DashboardQuickAccess> getQuickAccessList() {
        LambdaQueryWrapper<DashboardQuickAccess> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(DashboardQuickAccess::getCreateBy, SecurityUtils.getUsername());
        List<DashboardQuickAccess> dashboardQuickAccesses = dashboardQuickAccessMapper.selectList(queryWrapper);
        if (dashboardQuickAccesses.size() == 0){
            DashboardQuickAccess dashboardQuickAccess = new DashboardQuickAccess();
            dashboardQuickAccess.setTitle("快速入门");
            dashboardQuickAccess.setTitleOrder(0);
            dashboardQuickAccesses.add(dashboardQuickAccess);
            dashboardQuickAccess = new DashboardQuickAccess();
            dashboardQuickAccess.setTitle("网格查询");
            dashboardQuickAccess.setTitleOrder(1);
            dashboardQuickAccesses.add(dashboardQuickAccess);
            dashboardQuickAccess = new DashboardQuickAccess();
            dashboardQuickAccess.setTitle("我的客户");
            dashboardQuickAccess.setTitleOrder(2);
            dashboardQuickAccesses.add(dashboardQuickAccess);
            dashboardQuickAccess = new DashboardQuickAccess();
            dashboardQuickAccess.setTitle("走访视图");
            dashboardQuickAccess.setTitleOrder(3);
            dashboardQuickAccesses.add(dashboardQuickAccess);
            return dashboardQuickAccesses;
        }
        return dashboardQuickAccesses;
    }

    @Override
    public List<String> getRouterList() {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return dfs(menus);
    }

    /**
     * @return
     */
    @Override
    public List<LoadIndDmPaItemHome> getIndDmPaItemHomeList() {
        LambdaQueryWrapper<LoadIndDmPaItemHome> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LoadIndDmPaItemHome::getOuIpId,SecurityUtils.getDeptId());
        return  loadIndDmPaItemHomeMapper.selectList(queryWrapper);
    }

    /**
     * 获取预警信息列表--青田
     *
     * @return
     */
    @Override
    public CommonRespVO getWarnRespList(String type, Long pageNum, Long pageSize) {
        UrlRegistry  urlRegistry = urlRegistryMapper.selectUrlByCondition(SecurityUtils.getHeadId(), "1", type);
        if (urlRegistry == null || urlRegistry.getUrlPath() == null){
            throw new ServiceException("未找到对应的数据请求url");
        }
        String targetUrl = urlRegistry.getUrlPath();
        String authToken = getAuthToken();
        CommonRespVO respVO = new CommonRespVO();
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("page", pageNum);
        paramMap.put("limit", pageSize);
        String paramJson = JSON.toJSONString(paramMap);
        try{
            String resp = HttpUtils.doPost(targetUrl, paramJson, authToken);
            respVO = resp2VO(resp);
            return respVO;
        }catch (Exception e){
            log.error("请求发生异常: " + e.getMessage());
            redisCache.deleteObject(REDIS_KEY_TOKEN + SecurityUtils.getUsername());
            String newToken = getAuthToken();
            log.info("已刷新token, token: " + newToken);
        }
        return respVO;
    }

    /**
     * 获取特色标签--青田
     *
     * @return
     */
    @Override
    public CommonRespVO getTagList(String custId) {
        CommonRespVO respVO = new CommonRespVO();
        UrlRegistry urlRegistry = urlRegistryMapper.selectUrlByCondition(SecurityUtils.getHeadId(), "2", "特色标签");
        String authToken = getAuthToken();
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("csno", custId);
        String paramJson = JSON.toJSONString(paramMap);
        try {
            String resp = HttpUtils.doPost(urlRegistry.getUrlPath(), paramJson, authToken);
            respVO = resp2VO(resp);
            return respVO;
        } catch (Exception e) {
            log.error("请求发生异常: " + e.getMessage());
            redisCache.deleteObject(REDIS_KEY_TOKEN + SecurityUtils.getUsername());
            String newToken = getAuthToken();
            log.info("已刷新token, token: " + newToken);
        }
        return respVO;
    }

    /**
     * 获取token--青田
     *
     * @return
     */
    private String getAuthToken() {
        String token = redisCache.getCacheObject(REDIS_KEY_TOKEN + SecurityUtils.getUsername());
        log.info("尝试获取Redis存储的token: " + token);
        if (token != null && !token.isEmpty()){
            return token;
        }
        UrlRegistry urlRegistry = urlRegistryMapper.selectUrlByCondition(SecurityUtils.getHeadId(), "0", "token");
        if (urlRegistry == null || urlRegistry.getUrlPath() == null){
            throw new ServiceException("未找到对应的token请求url");
        }
        String tokenUrl = urlRegistry.getUrlPath();
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sub", SecurityUtils.getUsername());
        String param = JSON.toJSONString(paramMap);
        try{
            String tokenResp = HttpUtils.doPost(tokenUrl, param,null);
            if (tokenResp.isEmpty()){
                log.error("获取token为空-----token: " + tokenResp + ", url: " + tokenUrl);
                throw new ServiceException("获取token失败");
            }
            JSONObject respJson = JSONObject.parseObject(tokenResp);
            if (!respJson.containsKey("access_token")){
                log.error("返回值不包括token-----resp: " + respJson);
                throw new ServiceException("获取token失败");
            }
            token = respJson.getString("access_token");
            redisCache.setCacheObject(REDIS_KEY_TOKEN + SecurityUtils.getUsername(), token,12, TimeUnit.HOURS);
            log.info("已获取当前登陆账号" + SecurityUtils.getUsername() + "的token: " + token);
            return token;
        }catch (Exception e){
            log.error("请求token发生异常: " + e.getMessage());
            throw new ServiceException("获取token失败");
        }
    }

    /**
     * 返回结果类型转换
     * @param resp
     * @return
     */
    private CommonRespVO resp2VO(String resp){
        CommonRespVO commonRespVO = new CommonRespVO();
        List<Map<String, Object>> dataList = new ArrayList<>();
        if (resp == null || resp.isEmpty()){
            commonRespVO.setTotal(0L);
            commonRespVO.setData(dataList);
            log.info("当前登录账号:" + SecurityUtils.getUsername() + "， 获取返回内容: " + commonRespVO);
            return commonRespVO;
        }
        JSONObject jsonObject = JSON.parseObject(resp);
        JSONArray dataArray = jsonObject.getJSONArray("data");
        if (dataArray != null && !dataArray.isEmpty()){
            dataList = JSON.parseObject(dataArray.toJSONString(), List.class);
        }
        Long total = jsonObject.getLong("total");
        if (total == null){
            commonRespVO.setTotal(dataList.size());
        }else {
            commonRespVO.setTotal(total);
        }
        commonRespVO.setData(dataList);
        log.info("当前登录账号:" + SecurityUtils.getUsername() + "， 获取返回内容: " + commonRespVO);
        return commonRespVO;
    }


    private List<String> dfs(List<SysMenu> menus) {
        List<String> result = new ArrayList<>();
        if (menus.size() == 0){
            return result;
        }
        for (SysMenu menu : menus) {
            if (menu.getMenuType().equals("M")) {
                result.addAll(dfs(menu.getChildren()));
            }else{
                if (!menu.getIsLink()){
                    result.add(menu.getMenuName());
                }
            }
        }
        return result;
    }
}
