package com.reyun.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.reyun.dic.CustomMenuType;
import com.reyun.dic.VirtualEventType;
import com.reyun.model.*;
import com.reyun.repository.*;
import com.reyun.service.*;
import com.reyun.taskexecute.ReportCallable;
import com.reyun.util.*;

import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class RetentionServiceImpl implements RetentionService {

    private static Logger logger = LoggerFactory.getLogger(RetentionServiceImpl.class);

    @Autowired
    AppRepository appRepository;

    @Autowired
    RetentionRepository retentionRepository;

    @Autowired
    AccountRepository accountRepository;

    @Autowired
    UserGroupRepository usergroupRepository;


    @Autowired
    AuthService authService;

    @Autowired
    CustomMenuTemplateRepository customMenuTemplateRepository;

    @Autowired
    ConfigParamService configparamService;

    @Autowired
    VirtualEventService virtualEventService;

    @Autowired
    VirtualEventRepository virtualEventRepository;

    @Autowired
    ReportService reportService;

    private final static String TEMPLATE_TYPE_RETENTION = "retention";


    private Map<String, List> format(String reponse) {
        Map<String, List> result = new HashMap<>();
        List<List<Object>> valueResult = new ArrayList<>();

        try {
            ReportListResult content = new ObjectMapper().readValue(reponse, ReportListResult.class);
            List<Map<String, Object>> valList = content.getVal();
            if (valList.size() > 0) {

                Map<String, Object> valueMap = valList.get(0);
                List<Object> users = new ArrayList<>();
                for (String k : valueMap.keySet()) {
                    if (!"isall0".equals(k)) {
                        users.add(valueMap.get(k));
                    }
                }

                List<Object> trans4firstList = new ArrayList<>();
                List<Object> trans4lastList = new ArrayList<>();
                trans4firstList.add(100.00d);

                for (int i = 1; i < users.size(); i++) {

                    Double trans4first = Double.valueOf(users.get(i).toString()) * 100.0 / Double.valueOf(users.get(0).toString());
                    BigDecimal trans4firstb = BigDecimal.valueOf(users.get(0).toString().equals("0") ? 0 : trans4first);
                    Object trans4firstResult = trans4firstb.setScale(2, BigDecimal.ROUND_HALF_UP);
                    trans4firstList.add(trans4firstResult);

                    if (i > 0) {
                        Double trans4last = Double.valueOf(users.get(i).toString()) * 100.0 / Double.valueOf(users.get(i - 1).toString());
                        BigDecimal trans4lastb = BigDecimal.valueOf(users.get(i - 1).toString().equals("0") ? 0 : trans4last);
                        Object trans4lastResult = trans4lastb.setScale(2, BigDecimal.ROUND_HALF_UP);
                        trans4lastList.add(trans4lastResult);
                    }
                }

                valueResult.add(trans4firstList);
                valueResult.add(users);
                result.put("trans4last", trans4lastList);
            }
            result.put("val", valueResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public Retention create(Retention retention, Long account) {
        retention.setAccount(account);
        retention.setCreateAccount(account);
        App app = appRepository.findOne(retention.getApp());
        // String sqlTemp =
        // SqlUtil.generateRetentionSql(retention.getEventInfo(),
        // app.getAppkey());
        // retention.setQuerySql(sqlTemp);
        return retentionRepository.save(retention);
    }

    @Override
    public Retention update(Retention retention, Long account) {
        Retention dbRetention = retentionRepository.findOne(retention.getId());
        dbRetention.setName(retention.getName());
        dbRetention.setEventInfo(retention.getEventInfo());
        dbRetention.setModifyTime(new Date());
        dbRetention.setModifyAccount(account);
//		dbRetention.setRelativeTime(retention.getRelativeTime());
//		dbRetention.setStartDate(retention.getStartDate());
//		dbRetention.setEndDate(retention.getEndDate());
//		dbRetention.setView(retention.getView());
        dbRetention.setRetentionType(retention.getRetentionType());

        App app = appRepository.findOne(dbRetention.getApp());
        // String sqlTemp =
        // SqlUtil.generateRetentionSql(retention.getEventInfo(),
        // app.getAppkey());
        // dbRetention.setQuerySql(sqlTemp);

        List<CustomMenuTemplate> templateList = customMenuTemplateRepository.findAllTemplateByOriginal(dbRetention.getId(), TEMPLATE_TYPE_RETENTION);
        if(ValidateUtil.isValid(templateList)){
            List<CustomMenuTemplate> list = new ArrayList<>();
            for(CustomMenuTemplate cu : templateList){
                cu.setName(dbRetention.getName());
                list.add(cu);
            }
            customMenuTemplateRepository.save(list);
        }
        return retentionRepository.save(dbRetention);
    }

    @Override
    public Retention delete(Long id, Long account) {
        Retention dbRetention = retentionRepository.findOne(id);
        dbRetention.setModifyAccount(account);
        dbRetention.setModifyTime(new Date());
        dbRetention.setDelFlag(true);

        //查看是否存在看单之中,如果存在则删除。
        List<Long> templateList = customMenuTemplateRepository.findTemplateByOriginal(id, CustomMenuType.RETENTION.getKey());
        if (!CollectionUtils.isEmpty(templateList)) {
            customMenuTemplateRepository.deleteTemplateByIds(account, templateList);
        }

        return retentionRepository.save(dbRetention);
    }

    @Override
    public Retention findById(Long id) {
        return retentionRepository.findOne(id);
    }

    @Override
    public List<Retention> findByApp(Long app) {
        List<Retention> retentionList = retentionRepository.findAllByApp(app);
        List<Long> account = new ArrayList<>();
        for (Retention f : retentionList) {
            account.add(f.getCreateAccount());
        }
        Iterable<Account> accountList = accountRepository.findAll(account);
        Iterator<Account> a = accountList.iterator();
        Map<Long, String> idNameMap = new HashMap<>();
        while (a.hasNext()) {
            Account aObject = a.next();
            idNameMap.put(aObject.getId(), aObject.getEmail());
        }
        for (Retention f : retentionList) {
            f.setcAccount(idNameMap.get(f.getCreateAccount()));
        }
        return retentionList;
    }

    @Override
    public Retention validName(String name, Long app) {
        return retentionRepository.findByNameAndApp(name, app);
    }

    @Override
    public Map<String, List> retentionReport(String startDate, String endDate, boolean isList,
                                             String eventInfo, Long app, String usergroup, String dimention,
                                             String reportView, int interval, boolean isDevice, Long account, String retentiontype, boolean isProfile) {
        int retentions = 30;

        if (reportView.equals("week")) {
            retentions = 8;
        } else if (reportView.equals("month")) {
            retentions = 3;
        }
        if (DateUtil.compare_date(endDate, DateUtil.getBeforeDays(0)) == 1) {
            endDate = DateUtil.getBeforeDays(0);
        }
        String firstEndDate = endDate;
        String secondEndDate = "";
        if (reportView.equals("day")) {
            secondEndDate = DateUtil.getBeforeDays(endDate, -retentions);
            firstEndDate = DateUtil.getBeforeDays(firstEndDate, -1);
            String s1 = "";
        } else if (reportView.equals("week")) {
            secondEndDate = DateUtil.getLastDayOfWeek(DateUtil.getAfterWeeks(endDate, retentions));
        } else if (reportView.equals("month")) {
            secondEndDate = DateUtil.getLastdayOfMonth(DateUtil.getAfterMonths(endDate, retentions));
        }

        if (DateUtil.compare_date(secondEndDate, DateUtil.getBeforeDays(0)) == 1) {
            secondEndDate = DateUtil.getBeforeDays(0);
        }

        String secondStartDate = "";
        if (reportView.equals("day")) {
            secondStartDate = DateUtil.getBeforeDays(startDate, -1);
        } else if (reportView.equals("week")) {
            String s = "";
            secondStartDate = DateUtil.getFirstDayOfWeek(DateUtil.getAfterWeeks(startDate, 1));
        } else if (reportView.equals("month")) {
            secondStartDate = DateUtil.getFirstdayOfMonth(DateUtil.getAfterMonths(startDate, 1));
        }

        boolean isCompare = false;
        String dimentionKey = dimention;
        String sqlTemp = "";
        String totalSql = "";
        String usergroupName = "";
        boolean isUserGroup = false;
        App appObject = appRepository.findOne(app);

        sqlTemp = chooseVirtualEvent(retentiontype, app, eventInfo, appObject, reportView);
        //数据权限过滤

        String demoApps = configparamService.getConfigParamByKey("demo_appkey");
        List<String> demoAppList = Arrays.asList(demoApps.split(","));

        sqlTemp = sqlTemp.replace("$campaign","");

        if (!"install".equals(retentiontype)) {


            sqlTemp = sqlTemp.replace("$firststartdate", startDate + "");
            sqlTemp = sqlTemp.replace("$secondstartdate", secondStartDate);
            sqlTemp = sqlTemp.replace("$interval", interval + "");
            sqlTemp = sqlTemp.replace("$firstenddate", firstEndDate + "");
            sqlTemp = sqlTemp.replace("$secondenddate", secondEndDate + "");

            sqlTemp = sqlTemp.replaceAll("xwho", "a.xwho");
            sqlTemp = sqlTemp.replaceAll("xwhat", "a.xwhat");
            sqlTemp = sqlTemp.replaceAll("xwhen", "a.xwhen");
            sqlTemp = sqlTemp.replaceAll(" ds", " a.ds");
            sqlTemp = sqlTemp.replaceAll("_deviceid", "a._deviceid");

            String dataSource = "";
            String[] split = sqlTemp.split(" ");
            for (String s : split) {
                s.replaceAll(" ", "");
                if (s.startsWith("tkio_bigtable_view")) {
                    dataSource = s;
                    break;
                }
            }

            Pattern pattern = Pattern.compile("\\$dimentionselect");
            Matcher matcher = pattern.matcher(sqlTemp);
            sqlTemp = matcher.replaceFirst("\\$firstdimentionselect");

            String afterReplace = new String(dataSource + " a \\$joinprofile");
            String beforeReplace = new String(dataSource);

            sqlTemp = sqlTemp.replaceAll(beforeReplace, afterReplace);
            totalSql = new String(sqlTemp);

            usergroupName = "";
            isUserGroup = false;

            if (StringUtil.isEmpty(usergroup)) {
                sqlTemp = sqlTemp.replace("$usergroup", "");
                totalSql = totalSql.replace("$usergroup", "");
            } else {
                isCompare = true;
                isUserGroup = true;
                usergroupName = usergroupRepository.findOne(Long.valueOf(usergroup)).getName();
                totalSql = totalSql.replace("$usergroup", "");
                sqlTemp = sqlTemp
                        .replace(
                                "$usergroup",
                                String.format(
                                        " and a.xwho in (select objectid as xwho from %s where id='%s' and objecttype='xwho')",
                                        Constant.usergroupTable, usergroup));
            }

            //if (StringUtil.isEmpty(dimention) || dimention.equals("usergroup")) {
            if ("-all".equals(dimention) || "usergroup".equals(dimention)) {
                sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "");
                sqlTemp = sqlTemp.replace("$dimentionselect", "");
                sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                sqlTemp = sqlTemp.replace("$joinprofile", "");
                sqlTemp = sqlTemp.replace("$firstdimentionselect", "");
                sqlTemp = sqlTemp.replace("$dimentiongroupby", "");

                totalSql = totalSql.replace("$dimentionselect", "");
                totalSql = totalSql.replace("$dimentionwhere", "");
                totalSql = totalSql.replace("$dimentionaftergroupby", "");
                totalSql = totalSql.replace("$dimentiongroupby", "");
                totalSql = totalSql.replace("$joinprofile", "");
                totalSql = totalSql.replace("$firstdimentionselect", "");

            } else {
                isCompare = true;
                totalSql = totalSql.replace("$dimentionselect", "");
                totalSql = totalSql.replace("$dimentionwhere", "");
                totalSql = totalSql.replace("$dimentionaftergroupby", "");
                totalSql = totalSql.replace("$dimentiongroupby", "");
                totalSql = totalSql.replace("$joinprofile", "");
                totalSql = totalSql.replace("$firstdimentionselect", "");

                if (isProfile) {
                    sqlTemp = sqlTemp.replace("$dimentionselect", "b." + dimention + ",");
                    sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "," + " b." + dimention);
                    sqlTemp = sqlTemp.replace("$dimentiongroupby", " group by " + dimention);
                    sqlTemp = sqlTemp.replace("$firstdimentionselect", dimention + ", ");
                    sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                    String profileSource = Constant.profileTable + appObject.getAppkey();
                    sqlTemp = sqlTemp.replace("$joinprofile", "right join " + profileSource + " b on a.xwho=b.xwho");
                } else {
                    sqlTemp = sqlTemp.replace("$dimentionselect", "a." + dimention + ",");
                    sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "," + " a." + dimention);
                    sqlTemp = sqlTemp.replace("$dimentiongroupby", " group by " + dimention);
                    sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                    sqlTemp = sqlTemp.replace("$joinprofile", "");
                    sqlTemp = sqlTemp.replace("$firstdimentionselect", dimention + ", ");
                }
            }
        } else {

            sqlTemp = sqlTemp.replace("$firststartdate", startDate + "");
            sqlTemp = sqlTemp.replace("$secondstartdate", startDate);
            sqlTemp = sqlTemp.replace("$interval", interval + "");
            sqlTemp = sqlTemp.replace("$firstenddate", firstEndDate + "");
            sqlTemp = sqlTemp.replace("$secondenddate", secondEndDate + "");
            sqlTemp = sqlTemp.replaceAll("t0", "a");
            sqlTemp = sqlTemp.replaceAll("t1", "b");

            totalSql = new String(sqlTemp);

            usergroupName = "";
            isUserGroup = false;

            if (StringUtil.isEmpty(usergroup)) {
                sqlTemp = sqlTemp.replace("$usergroup", "");
                totalSql = totalSql.replace("$usergroup", "");
            } else {
                String s;
                isCompare = true;
                isUserGroup = true;
                usergroupName = usergroupRepository.findOne(Long.valueOf(usergroup)).getName();
                totalSql = totalSql.replace("$usergroup", "");
                sqlTemp = sqlTemp.replace("$usergroup",
                        String.format(
                                " and a.xwho in (select objectid as xwho from %s where id='%s' and objecttype='xwho')",
                                Constant.usergroupTable, usergroup));
            }

            //if (StringUtil.isEmpty(dimention) || dimention.equals("usergroup")) {
            if ("-all".equals(dimention) || "usergroup".equals(dimention)) {
                sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "");
                sqlTemp = sqlTemp.replace("$dimentionselect", "");
                sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                sqlTemp = sqlTemp.replace("$firstdimentionselect", "");
                sqlTemp = sqlTemp.replace("$dimentiongroupby", "");

                totalSql = totalSql.replace("$dimentionselect", "");
                totalSql = totalSql.replace("$dimentionwhere", "");
                totalSql = totalSql.replace("$dimentionaftergroupby", "");
                totalSql = totalSql.replace("$dimentiongroupby", "");
                totalSql = totalSql.replace("$firstdimentionselect", "");

            } else {
                isCompare = true;
                totalSql = totalSql.replace("$dimentionselect", "");
                totalSql = totalSql.replace("$dimentionwhere", "");
                totalSql = totalSql.replace("$dimentionaftergroupby", "");
                totalSql = totalSql.replace("$dimentiongroupby", "");
                totalSql = totalSql.replace("$firstdimentionselect", "");

                if (isProfile) {
                    sqlTemp = sqlTemp.replace("$dimentionselect", "b." + dimention + ",");
                    sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "," + " b." + dimention);
                    sqlTemp = sqlTemp.replace("$dimentiongroupby", " group by " + dimention);
                    sqlTemp = sqlTemp.replace("$firstdimentionselect", dimention + ", ");
                    sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                } else {
                    sqlTemp = sqlTemp.replace("$dimentionselect", "a." + dimention + ",");
                    sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "," + " a." + dimention);
                    sqlTemp = sqlTemp.replace("$dimentiongroupby", " group by " + dimention);
                    sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                    sqlTemp = sqlTemp.replace("$firstdimentionselect", dimention + ", ");
                }
            }
        }


        Map<String, List> result = new HashMap<>();
        try {
            if (isCompare) {

                if (isUserGroup) {
                    dimentionKey = "usergroup";
                }

                Map<String, String> dimentionMap = new HashMap<>();
                if (dimentionKey.equals("_campaignid") || dimentionKey.equals("_cid")) {
                    Account accountObject = accountRepository.findOne(account);
                    String url = Constant.trackingUrl + "/api/"+ app +"/channel/findchannelcamp4io?appkey=" + appObject.getAppkey() + "&email=" + accountObject.getEmail();
                    String response = HttpClientUtil.doHttpGetRequest(url, "io");
                    if (!StringUtil.isEmpty(response)) {
                        try {
                            JSONObject ob = JSONObject.fromObject(response);
                            JSONObject content = ob.getJSONObject("content");
                            if (dimentionKey.equals("_cid")) {
                                JSONObject channelObject = content.getJSONObject("channel");
                                ObjectMapper mapper = new ObjectMapper();
                                dimentionMap = mapper.readValue(channelObject.toString(), Map.class);
                            }
                            if (dimentionKey.equals("_campaignid")) {
                                JSONObject campObject = content.getJSONObject("campaign");
                                ObjectMapper mapper = new ObjectMapper();
                                dimentionMap = mapper.readValue(campObject.toString(), Map.class);
                            }

                        } catch (Exception e) {
                            logger.error("fail to get channel or campaign name");
                        }
                    }

                }

                if ("-all".equals(dimention)) {
                    sqlTemp = new String(totalSql);
                }


                // 创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2);
                // 创建两个有返回值的任务
                ReportCallable c1 = new ReportCallable("retention", totalSql, null, startDate, endDate, dimentionKey, isCompare, true,
                        interval, reportView, null, "", null, null, appObject.getAppkey(), null);
                ReportCallable c2 = new ReportCallable("retention", sqlTemp, null, startDate, endDate, dimentionKey, isCompare, false,
                        interval, reportView, usergroup, usergroupName, null, null, appObject.getAppkey(), dimentionMap);
                // 执行任务并获取Future对象
                Future<Map<String, List>> f1 = pool.submit(c1);
                Future<Map<String, List>> f2 = pool.submit(c2);
                // 从Future对象上获取任务的返回值，并输出到控制台
                try {
                    result = f1.get();
                    List<Map<String, Object>> val1 = result.get("val");
                    if (!result.containsKey("isempty") || "usergroup".equals(dimention)) {
                        Map<String, List> result2 = f2.get();
                        List<Map<String, Object>> val2 = result2.get("val");
                        val1.addAll(val2);
                    }
                    result.put("val", val1);
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
                // 关闭线程池
                pool.shutdown();
            } else {

                Map<String, String> conditions = new HashMap<String, String>();
                conditions.put("sql", sqlTemp);
                conditions.put("dbtype", "presto");
                conditions.put("datatype", "list");
                conditions.put("reportname", "retention");
                conditions.put("appid", appObject.getAppkey());

                Map<String, List> responseJson = new HashMap<>();

                String url = "";

                if (demoAppList.contains(appObject.getAppkey())) {
                    try {
                        url = Constant.demoUrl + "/api/trackingio/retentionall/" + appObject.getAppkey();
                        url = getDemoReportUrlByView(url, reportView);
                        String responseStr = HttpClientUtil.doHttpPostRequest(url, "trackingio", conditions);
                        ObjectMapper mapper = new ObjectMapper();
                        responseJson = mapper.readValue(responseStr, Map.class);
                    } catch (Exception e) {
                        logger.error("fail to get demo data......");
                    }

                } else {
                    responseJson = reportService.reportBySql(conditions);
                }



                result = SqlUtil.format4Retention(responseJson, interval, dimentionKey, reportView, usergroup, usergroupName, null, null);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 获取DEMO账号的REPORT URL
     * created by sunhao 20170517
     */
    private String getDemoReportUrlByView(String url, String reportView) {

        switch (reportView) {
            case "day":
                url += "/day/14";
                break;
            case "week":
                url += "/week/12";
                break;
            case "month":
                url += "/month/6";
                break;
        }

        return url;
    }

    @Override
    public Map<String, List> retentionDetailReport(Account loginAccount, String startDate, String endDate, boolean isList, String eventInfo, Long app,
                                                   String usergroup, String dimention, String reportView, int interval, boolean isDevice, String retentiontype, boolean isProfile) {

        int retentions = 30;

        if (reportView.equals("week")) {
            retentions = 8;
        } else if (reportView.equals("month")) {
            retentions = 3;
        }

        if (DateUtil.compare_date(endDate, DateUtil.getBeforeDays(0)) == 1) {
            endDate = DateUtil.getBeforeDays(0);
        }

        String firstEndDate = endDate;
        String secondEndDate = "";
        if (reportView.equals("day")) {
            secondEndDate = DateUtil.getBeforeDays(endDate, -retentions);
            firstEndDate = DateUtil.getBeforeDays(firstEndDate, -1);
        } else if (reportView.equals("week")) {
            secondEndDate = DateUtil.getLastDayOfWeek(DateUtil.getAfterWeeks(endDate, retentions));
        } else if (reportView.equals("month")) {
            secondEndDate = DateUtil.getLastdayOfMonth(DateUtil.getAfterMonths(endDate, retentions));
        }

        if (DateUtil.compare_date(secondEndDate, DateUtil.getBeforeDays(0)) == 1) {
            secondEndDate = DateUtil.getBeforeDays(0);
        }

        String secondStartDate = "";
        if (reportView.equals("day")) {
            secondStartDate = DateUtil.getBeforeDays(startDate, -1);
        } else if (reportView.equals("week")) {
            secondStartDate = DateUtil.getFirstDayOfWeek(DateUtil.getAfterWeeks(startDate, 1));
        } else if (reportView.equals("month")) {
            secondStartDate = DateUtil.getFirstdayOfMonth(DateUtil.getAfterMonths(startDate, 1));
        }

        String sqlTemp = "";
        App appObject = appRepository.findOne(app);


        sqlTemp = chooseVirtualEvent(retentiontype, app, eventInfo, appObject, reportView);
        //数据权限过滤

        sqlTemp = sqlTemp.replace("$campaign","");

        if (!"install".equals(retentiontype)) {

            sqlTemp = sqlTemp.replace("$firststartdate", startDate + "");
            sqlTemp = sqlTemp.replace("$secondstartdate", secondStartDate);
            sqlTemp = sqlTemp.replace("$interval", interval + "");
            sqlTemp = sqlTemp.replace("$firstenddate", firstEndDate + "");
            sqlTemp = sqlTemp.replace("$secondenddate", secondEndDate + "");

            sqlTemp = sqlTemp.replaceAll("xwho", "a.xwho");
            sqlTemp = sqlTemp.replaceAll("xwhat", "a.xwhat");
            sqlTemp = sqlTemp.replaceAll("xwhen", "a.xwhen");
            sqlTemp = sqlTemp.replaceAll(" ds", " a.ds");
            sqlTemp = sqlTemp.replaceAll("_deviceid", "a._deviceid");

            String dataSource = "";
            String[] split = sqlTemp.split(" ");
            for (String s : split) {
                s.replaceAll(" ", "");
                if (s.startsWith("tkio_bigtable_view")) {
                    dataSource = s;
                    break;
                }
            }

            Pattern pattern = Pattern.compile("\\$dimentionselect");
            Matcher matcher = pattern.matcher(sqlTemp);
            sqlTemp = matcher.replaceFirst("\\$firstdimentionselect");

            String afterReplace = new String(dataSource + " a \\$joinprofile");
            String beforeReplace = new String(dataSource);

            sqlTemp = sqlTemp.replaceAll(beforeReplace, afterReplace);

            if (StringUtil.isEmpty(usergroup)) {
                sqlTemp = sqlTemp.replace("$usergroup", "");
            } else {
                sqlTemp = sqlTemp
                        .replace(
                                "$usergroup",
                                String.format(
                                        " and a.xwho in (select objectid as xwho from %s where id='%s' and objecttype='xwho')",
                                        Constant.usergroupTable, usergroup));
            }

            sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "");
            sqlTemp = sqlTemp.replace("$dimentionselect", "");
            sqlTemp = sqlTemp.replace("$firstdimentionselect", "");
            sqlTemp = sqlTemp.replace("$dimentiongroupby", "");

            if (isProfile) {
                String profileSource = Constant.profileTable + appObject.getAppkey();
                sqlTemp = sqlTemp.replace("$joinprofile", "right join " + profileSource + " b on a.xwho=b.xwho");
            } else {
                sqlTemp = sqlTemp.replace("$joinprofile", "");
            }

            if (StringUtil.isEmpty(dimention)) {
                sqlTemp = sqlTemp.replace("$dimentionwhere", "");
            } else {
                JSONObject dimentionObject = JSONObject.fromObject(dimention);

                if (dimentionObject.size() > 0) {
                    String key = dimentionObject.keys().next().toString();
                    String value = dimentionObject.getString(key);
                    String type = dimentionObject.getString("type");
                    if (StringUtil.isEmpty(value)) {
                        String s1;
                        sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                    } else {
                        String dimentionwhere = StringUtil.getSql(key, value, "in", type, "").trim();
                        if (isProfile) {
                            sqlTemp = sqlTemp.replace("$dimentionwhere", String.format(" and b.%s", dimentionwhere));
                        } else {
                            sqlTemp = sqlTemp.replace("$dimentionwhere", String.format(" and a.%s", dimentionwhere));
                        }
                    }
                }
            }
        } else {
            sqlTemp = sqlTemp.replace("$firststartdate", startDate + "");
            sqlTemp = sqlTemp.replace("$secondstartdate", startDate);
            sqlTemp = sqlTemp.replace("$interval", interval + "");
            sqlTemp = sqlTemp.replace("$firstenddate", firstEndDate + "");
            sqlTemp = sqlTemp.replace("$secondenddate", secondEndDate + "");
            sqlTemp = sqlTemp.replaceAll("t0", "a");
            sqlTemp = sqlTemp.replaceAll("t1", "b");

            if (StringUtil.isEmpty(usergroup)) {
                sqlTemp = sqlTemp.replace("$usergroup", "");
            } else {
                sqlTemp = sqlTemp.replace("$usergroup",
                        String.format(
                                " and a.xwho in (select objectid as xwho from %s where id='%s' and objecttype='xwho')",
                                Constant.usergroupTable, usergroup));
            }

            sqlTemp = sqlTemp.replace("$dimentionaftergroupby", "");
            sqlTemp = sqlTemp.replace("$dimentionselect", "");
            sqlTemp = sqlTemp.replace("$firstdimentionselect", "");
            sqlTemp = sqlTemp.replace("$dimentiongroupby", "");

            if (StringUtil.isEmpty(dimention)) {
                sqlTemp = sqlTemp.replace("$dimentionwhere", "");
            } else {
                JSONObject dimentionObject = JSONObject.fromObject(dimention);

                if (dimentionObject.size() > 0) {
                    String key = dimentionObject.keys().next().toString();
                    String value = dimentionObject.getString(key);
                    String type = dimentionObject.getString("type");

                    if (StringUtil.isEmpty(value)) {
                        sqlTemp = sqlTemp.replace("$dimentionwhere", "");
                    } else {
                        // value = value.replace(",", "','");
                        String dimentionwhere = StringUtil.getSql(key, value, "in", type, "").trim();
                        if (isProfile) {
                            sqlTemp = sqlTemp.replace("$dimentionwhere", String.format(" and b.%s", dimentionwhere));
                        } else {
                            sqlTemp = sqlTemp.replace("$dimentionwhere", String.format(" and a.%s", dimentionwhere));
                        }
                    }
                }
            }
        }


        if (isDevice) {
            sqlTemp = sqlTemp.replace("xwho", "_deviceid");
        }

        Map<String, String> conditions = new HashMap<String, String>();
        conditions.put("sql", sqlTemp);
        conditions.put("dbtype", "presto");
        conditions.put("datatype", "list");
        conditions.put("reportname", "retention");
        conditions.put("appid", appObject.getAppkey());

        Map<String, List> result = new HashMap<>();
        try {
            Map<String, List> responseJson =new HashMap<>();
            String demoApps = configparamService.getConfigParamByKey("demo_appkey");
            List<String> demoAppList = Arrays.asList(demoApps.split(","));
            if (demoAppList.contains(appObject.getAppkey())) {

                String url = Constant.demoUrl + "/api/trackingio/retentiondetail/" + appObject.getAppkey();
                url = getDemoReportUrlByView(url, reportView);
                String responseStr = HttpClientUtil.doHttpPostRequest(url, "trackingio", conditions);
                ObjectMapper mapper = new ObjectMapper();
                responseJson = mapper.readValue(responseStr, Map.class);
            } else {
                responseJson = reportService.reportBySql(conditions);
            }
            result = SqlUtil.format4DetailList(responseJson, startDate, interval, reportView);

        } catch (Exception e) {
            List<Map<String, Object>> val = new ArrayList<>();
            List<String> columnkey = new ArrayList<>();
            result.put("val", val);
            result.put("columnkey", columnkey);
            result.put("name", columnkey);
            logger.debug("fail to get retention detail data.......");
        }
        return result;
    }

    private Map<String, List> getRetentionResult(boolean isDetail) {

        Map<String, List> result = new HashMap<>();

        List<Map<String, Object>> val = new ArrayList<>();
        List<String> columnkey = new ArrayList<>();
        List<String> name = new ArrayList<>();

        if (!isDetail) {
            Map<String, Object> map = new HashMap<>();
            map.put("ds", "整体");
            map.put("init", 0);
            map.put("retention1", 0);
            map.put("retention2", 0);
            map.put("retention3", 0);
            map.put("retention4", 0);
            map.put("retention5", 0);
            map.put("retention6", 0);
            map.put("retention7", 0);
            map.put("retention14", 0);
            map.put("rate_retention30", 0d);
            map.put("rate_retention1", 0d);
            map.put("rate_retention2", 0d);
            map.put("rate_retention3", 0d);
            map.put("rate_retention4", 0d);
            map.put("rate_retention5", 0d);
            map.put("rate_retention6", 0d);
            map.put("rate_retention7", 0d);
            map.put("rate_retention14", 0d);
            map.put("rate_retention30", 0d);
            val.add(map);
        }

        columnkey.add("ds");
        columnkey.add("init");
        columnkey.add("retention1");
        columnkey.add("retention2");
        columnkey.add("retention3");
        columnkey.add("retention4");
        columnkey.add("retention5");
        columnkey.add("retention6");
        columnkey.add("retention7");
        columnkey.add("retention14");
        columnkey.add("retention30");

        name.add("日期");
        name.add("初始日");
        name.add("1天后");
        name.add("2天后");
        name.add("3天后");
        name.add("4天后");
        name.add("5天后");
        name.add("6天后");
        name.add("7天后");
        name.add("14天后");
        name.add("30天后");

        result.put("val", val);
        result.put("columnkey", columnkey);
        result.put("name", name);
        result.put("key", name.subList(1, name.size()));

        return result;
    }



    private String chooseVirtualEvent(String retentiontype, Long app, String eventInfo, App appObject, String reportView) {
        String s = "";
        if (VirtualEventType.ACTIVEEVENT.getCode().equals(retentiontype)) {
            List<VirtualEvent> eventList = virtualEventRepository.findEventListByAppIdAndType(app, retentiontype);
            if (CollectionUtils.isEmpty(eventList)) {
                eventInfo = configparamService.getConfigParamByKey("default_event");
            } else {
                eventInfo = eventList.get(0).getEventList();
            }
            s = SqlUtil.generateVirtualRetentionSql(eventInfo, appObject.getAppkey(), reportView);
        } else if (VirtualEventType.INSTALEVENT.getCode().equals(retentiontype)) {
            List<VirtualEvent> eventList = virtualEventRepository.findEventListByAppIdAndType(app, VirtualEventType.ACTIVEEVENT.getCode());
            if (CollectionUtils.isEmpty(eventList)) {
                eventInfo = configparamService.getConfigParamByKey("default_event");
            } else {
                eventInfo = eventList.get(0).getEventList();
            }
            s = SqlUtil.generateInstallVirtualRetentionSql(eventInfo, appObject.getAppkey(), reportView);
        } else {
            s = SqlUtil.generateRetentionSql(eventInfo, appObject.getAppkey(), reportView);
        }
        return s;
    }

}



