package com.usoftchina.bi.server.service.dashboard;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.usoftchina.bi.core.exception.MyException;
import com.usoftchina.bi.core.utils.EncryUtil;
import com.usoftchina.bi.server.dao.chart.ChartsConfigMapper;
import com.usoftchina.bi.server.dao.dashboard.DashboardsMapper;
import com.usoftchina.bi.server.dao.user.UserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import com.usoftchina.bi.server.model.bo.DashOrder;
import com.usoftchina.bi.server.model.bo.ShareReqBO;
import com.usoftchina.bi.server.model.po.ChartConfig;
import com.usoftchina.bi.server.model.po.Dashboards;
import com.usoftchina.bi.core.base.RepCode;
import com.usoftchina.bi.core.base.RepEntity;
import com.usoftchina.bi.core.base.TestPage;
import com.usoftchina.bi.server.model.vo.configVo.ChangeOrderInfo;
import com.usoftchina.bi.server.model.vo.configVo.DashboardsInfo;
import com.usoftchina.bi.server.model.vo.dataVo.DashboardCopyInfo;
import com.usoftchina.bi.server.model.vo.dataVo.DashboardOrderInfo;
import com.usoftchina.bi.server.model.vo.dataVo.DataSourceCopyInfo;
import com.usoftchina.bi.server.service.chart.ChartsUtilService;
import com.usoftchina.bi.core.utils.GetTokenDataUtil;
import com.usoftchina.bi.server.service.dataSource.DataConnectorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class DashboardsService {
    @Autowired
    DashboardsMapper dashboardsMapper;
    @Autowired
    ObjectMapper objectMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    ChartsUtilService chartsUtilService;
    @Autowired
    private DataConnectorService dataConnectorService;
    @Autowired
    private ChartsConfigMapper chartsConfigMapper;

    private static final Logger LOGGER = LoggerFactory.getLogger(DashboardsService.class);

    /*
    保存看板
     */
    public RepEntity setDashboards(String token, DashboardsInfo dashboardsInfo) {
        //校验报表编号是否已存在
        validCode(dashboardsInfo.getBdCode(), dashboardsInfo.getId());
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        String name = stringMap.get("name");
        Dashboards dashboards = new Dashboards();
        BeanUtils.copyProperties(dashboardsInfo, dashboards);
        dashboards.setCreateBy(name);
        dashboards.setCreateId(userId);
        if (dashboardsInfo.getFilters() == null){
            dashboardsInfo.setFilters("");
        }
        dashboardsMapper.setDashboards(dashboards);
        int id = dashboards.getId();
        //保存报表图表关联关系
        String chartIds = dashboardsInfo.getChartIds();
        if (!StringUtils.isEmpty(chartIds)) {
            dashboardsMapper.saveDashboardChartRelation(id, chartIds.split(","));
        }
        return new RepEntity(RepCode.success, id);
    }

    /*
    更新看板
     */
    public RepEntity updateDashboards(String token, DashboardsInfo dashboardsInfo) {
        //校验报表编号是否已存在
        validCode(dashboardsInfo.getBdCode(), dashboardsInfo.getId());
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        String name = stringMap.get("name");
        int createId = dashboardsMapper.getCreateIdById(dashboardsInfo.getId());
        if (userId != createId) {
            return new RepEntity(RepCode.NoAuthority);
        }
        Dashboards dashboards = new Dashboards();
        BeanUtils.copyProperties(dashboardsInfo, dashboards);
        dashboards.setCreateBy(name);
        dashboards.setCreateId(userId);
        if (dashboardsInfo.getFilters() == null){
            dashboardsInfo.setFilters("");
        }
        dashboardsMapper.updateDashboards(dashboards);
        //更新报表图表关系
        int dashboardId = dashboardsInfo.getId();
        String chartIds = dashboardsInfo.getChartIds();
        String oldChartIds = dashboardsMapper.getChartIdsById(dashboardId);
        if (!StringUtils.isEmpty(oldChartIds)) {
            if (StringUtils.isEmpty(chartIds)) {    //旧不为空 & 新为空
                dashboardsMapper.deleteDashboardChartRelation(dashboardId);
            }else {                                 //旧不为空 & 新不为空
                if (!oldChartIds.equals(dashboardsInfo.getChartIds())) {
                    dashboardsMapper.deleteDashboardChartRelation(dashboardId);
                    dashboardsMapper.saveDashboardChartRelation(dashboardId, chartIds.split(","));
                }
            }
        }else {
            //旧为空  & 新不为空
            if (!StringUtils.isEmpty(chartIds)) {
                dashboardsMapper.saveDashboardChartRelation(dashboardId, chartIds.split(","));
            }
        }
        return new RepEntity(RepCode.success);
    }

    /**
     * 校验编号是否存在
     * @param code
     * @param id
     */
    private void validCode(String code, int id) {
        if (!StringUtils.isEmpty(code)) {
            int count = dashboardsMapper.countBdCodeById(code, id);
            if (count > 0) {
                throw new MyException("编号" + code + "已存在");
            }
        }
    }

    /*
    删除看板
     */
    public RepEntity delDashboards(String token, Integer id) {
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        int createId = dashboardsMapper.getCreateIdById(id);
        if (userId != createId) {
            return new RepEntity(RepCode.NoAuthority);
        }
        dashboardsMapper.delDashboards(id);
        //删除看板-图表关联关系
        dashboardsMapper.deleteDashboardChartRelation(id);
        return new RepEntity(RepCode.success);
    }

    /*
    查看看板
     */
    public RepEntity getListDashboards(String token, TestPage testPage) {
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int id = Integer.parseInt(stringMap.get("id"));
        List<Dashboards> getListDashboards = dashboardsMapper.getListDashboards(id, testPage.enablePaging());
        PageInfo<Dashboards> pageInfo = new PageInfo<>(getListDashboards);
        return new RepEntity(RepCode.success, pageInfo);
    }

    /*
    查看单个看板
     */
    public RepEntity getDashboards(String token, int id) {
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        Dashboards dashboards = dashboardsMapper.getDashboards(userId, id);
        if (dashboards == null){
            return new RepEntity(RepCode.DashboardNonExistent);
        }
        return new RepEntity(RepCode.success, dashboards);
    }

    /**
     * 通过code查看单个看板
     * @param code
     * @return
     */
    public RepEntity getDashboardByCode(String code) {
        code = validAndDes(code);
        Dashboards dashboard = dashboardsMapper.getDashboardByCode(code);
        if (ObjectUtils.isEmpty(dashboard)) {
            return new RepEntity(RepCode.DashboardNonExistent.getCode(), String.format(RepCode.DashboardNotExist.getMsg(), code), null);
        }
        Dashboards dashboards = dashboardsMapper.getDashboards(dashboard.getCreateId(), dashboard.getId());
        if (dashboards == null){
            return new RepEntity(RepCode.DashboardNonExistent);
        }
        return new RepEntity(RepCode.success, dashboards);
    }

    private String validAndDes(String code) {
        String message = EncryUtil.decryptBiCode(code);
        String[] params = message.split("&");
        if (params.length == 2) {
            if (System.currentTimeMillis() - Long.valueOf(params[1]) > 15 * 60 * 1000) {
                LOGGER.error("now={}, params[1]={}, diff={}", System.currentTimeMillis(), params[1], System.currentTimeMillis()-Long.valueOf(params[1]));
                throw new MyException("请求超时");
            }
            return params[0];
        }else {
            throw new MyException("请求参数个数错误");
        }
    }

    /**
     * 生成分享链接参数
     * @param shareReqBO
     * @return
     */
    public RepEntity shareDashBoard(ShareReqBO shareReqBO) {
        Long endTime = new Double(System.currentTimeMillis() + shareReqBO.getDelay() * 24 * 60 * 60 * 1000).longValue();
        String data = "id=" + shareReqBO.getId() + "&endTime=" + endTime;
        String encodeData = new String(EncryUtil.encryptBiCode(data));
        return new RepEntity(RepCode.success, encodeData);
    }

    /**
     * 链接参数解析
     * @param data
     * @return
     */
    private Map<String, String> parseParams(String data) {
        String decodeData = new String(EncryUtil.decryptBiCode(data));
        Map<String, String> map = new HashMap<>();
        int firstEndIndex = decodeData.indexOf("&");
        map.put("id", decodeData.substring(3, firstEndIndex));
        map.put("endTime", decodeData.substring(firstEndIndex + 9));
        return map;
    }

    /**
     * 通过分享链接获取看板信息
     * @param data
     * @return
     */
    public RepEntity getSharedDashboard(String data){
        Map<String, String> params = parseParams(data);
        Long endTime = Long.valueOf(params.get("endTime"));
        if (System.currentTimeMillis() > endTime) {
            throw new MyException("分享链接已过期");
        }
        int id = Integer.valueOf(params.get("id"));
        int creatorId = dashboardsMapper.getCreateIdById(id);
        Dashboards dashboards = dashboardsMapper.getDashboards(creatorId, id);
        if (dashboards == null){
            return new RepEntity(RepCode.DashboardNonExistent);
        }
        return new RepEntity(RepCode.success, dashboards);
    }

    /*
    转交看板
     */
    public RepEntity changeDashOrder(String token, ChangeOrderInfo changeOrderInfo) {
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        int createId = dashboardsMapper.getCreateIdById(changeOrderInfo.getId());
        if (userId != createId) {
            return new RepEntity(RepCode.NoAuthority);
        }
        String name = userMapper.getName(changeOrderInfo.getUserId());
        dashboardsMapper.changeDashOrder(name, changeOrderInfo.getUserId(), changeOrderInfo.getId());
        return new RepEntity(RepCode.success);
    }

    /*
    查看看板分发对象
     */
    public RepEntity getDashOrder(String token, int dashId) {
        Map<String, String> stringMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(stringMap.get("id"));
        int createId = dashboardsMapper.getCreateIdById(dashId);
        if (userId != createId) {
            return new RepEntity(RepCode.NoAuthority);
        }

        List<DashOrder> userNames = new ArrayList<>();
        List<DashOrder> groupNames = new ArrayList<>();
        List<String> type = dashboardsMapper.getType(dashId);
        Iterator isType = type.iterator();
        while (isType.hasNext()){
            String ty = String.valueOf(isType.next());
            if ("1".equals(ty)){
                userNames = dashboardsMapper.getOrderName(dashId);
            }else {
                groupNames = dashboardsMapper.getOrderGroupName(dashId);
            }
        }
        DashboardOrderInfo dashboardOrderInfo = new DashboardOrderInfo();
        dashboardOrderInfo.setUserNames(userNames);
        dashboardOrderInfo.setGroupNames(groupNames);
        return new RepEntity(RepCode.success, dashboardOrderInfo);
    }

    /**
     * 复制看板
     * @param dashboardCopyInfo
     * @return
     */
    @Transactional
    public RepEntity copy(String token, DashboardCopyInfo dashboardCopyInfo) {
        Map<String, String> resultMap = GetTokenDataUtil.getTokenData(token);
        int userId = Integer.parseInt(resultMap.get("id"));
        String userName = resultMap.get("name");
        int dashboardId = dashboardCopyInfo.getDashboardId(),
            dataSourceId = dashboardCopyInfo.getDataSourceId();
        List<String> idList = new ArrayList<>();
        Map<String, String> idMap = new HashMap<>();
        //复制图表
        String chartIds = dashboardsMapper.getChartIdsById(dashboardId);
        if (!StringUtils.isEmpty(chartIds)) {
            String[] idArray = chartIds.split(",");
            for (int i = 0, len = idArray.length; i < len; i++) {
                ChartConfig chartConfig = chartsConfigMapper.getOneChart(Integer.valueOf(idArray[i]));
                int oldChartId = chartConfig.getChartId();
                chartConfig.setChartName(chartConfig.getChartName() + "_副本");
                chartConfig.setCreateBy(userName);
                chartConfig.setCreateId(userId);
                int dataId = dataConnectorService.copyDataSource(token, new DataSourceCopyInfo(chartConfig.getDataId(), dataSourceId)).getData();
                chartConfig.setDataId(dataId);
                chartsConfigMapper.insertCharts(chartConfig);
                int newChartId = chartConfig.getChartId();
                idMap.put(String.valueOf(oldChartId), String.valueOf(newChartId));
                idList.add(String.valueOf(newChartId));
            }
        }
        //复制报表
        int dashboardCreatorId = dashboardsMapper.getCreateIdById(dashboardId);
        Dashboards dashboards = dashboardsMapper.getDashboards(dashboardCreatorId, dashboardId);
        dashboards.setBdName(dashboards.getBdName() + "_副本");
        JSONArray jsonArray = JSON.parseArray(dashboards.getBdConfiguration());
        for (int i = 0, len = jsonArray.size(); i < len; i++) {
            JSONObject json = jsonArray.getJSONObject(i);
            if (!"richText".equals(json.getString("viewType"))) {
                String newId = idMap.get(json.getString("code"));
                json.put("code", newId);
                json.put("chartCode", newId);
            }
        }
        dashboards.setBdConfiguration(JSON.toJSONString(jsonArray));
        dashboards.setCreateBy(userName);
        dashboards.setCreateId(userId);
        dashboards.setDemo(false);
        dashboards.setBdCode("");
        dashboardsMapper.setDashboards(dashboards);
        String[] ids = String.join(",", idList).split(",");
        dashboardsMapper.saveDashboardChartRelation(dashboards.getId(), ids);
        return new RepEntity(RepCode.success, dashboards.getId());
    }

}
