package com.reyun.taskexecute;

import com.reyun.context.AppUtils;
import com.reyun.dic.DownloadStatusEnumType;
import com.reyun.dic.FunctionEnumType;
import com.reyun.model.*;
import com.reyun.service.*;
import com.reyun.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by zxy on 17/4/27.
 * description:生成报表导出结果文件
 */
public class ExportReportThread extends Thread {

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

    private ExportReportInfo export;

    private ExportReportInfoService exportService = AppUtils.getApplicationContext().getBean(ExportReportInfoService.class);


    private FunnelService funnelService = AppUtils.getApplicationContext().getBean(FunnelService.class);

    private AuthService authService = AppUtils.getApplicationContext().getBean(AuthService.class);

    private EventStatsService eventStatsService = AppUtils.getApplicationContext().getBean(EventStatsService.class);

    private ComplicateEventsService complicateEventsService = AppUtils.getApplicationContext().getBean(ComplicateEventsService.class);

    private RetentionService retentionService = AppUtils.getApplicationContext().getBean(RetentionService.class);

    private static final String S3_DOWNLOAD_BUCKET = Constant.bucket;

    private static final String DOWNLOAD_PATH = "trackingio/reportdownload/";

    private static final String VIEW_TYPE_DAY = "day";
    private static final String VIEW_TYPE_WEEK = "week";
    private static final String VIEW_TYPE_MONTH = "month";


    public ExportReportThread(ExportReportInfo export) {
        this.export = export;
        this.setName("ExportReportThread");
    }

    @Override
    public void run() {

        boolean success = true;

        try {

            Map<String, String> conditions = ExportReportUtil.changeCondition2Map(export.getConditions());
            StringBuffer sb = new StringBuffer();
            Account account = authService.getSubAccountAuthById(export.getAccount());

            if (export.getFunctionType().equals(FunctionEnumType.FUNNEL.getKey())) {

                //必传参数：funnel、startdate、enddate
                Long funnel = export.getFunctionId();
                String startDate = conditions.get("startdate");
                String endDate = conditions.get("enddate");

                if (funnel == null || StringUtil.isEmpty(startDate) || StringUtil.isEmpty(endDate)) {
                    logger.info("漏斗下载条件不全：startDate:" + startDate + ", endDate:" + endDate + ", funnel:" + funnel);
                    success = false;
                } else {

                    String userGroupStr = conditions.get("usergroupid");
                    String dimensionStr = conditions.get("dimention");
                    String isDeviceStr = conditions.get("isdevice");
                    boolean isList = conditions.get("datatype") != null && "list".equals(conditions.get("datatype"));
                    boolean isDevice = !StringUtil.isEmpty(isDeviceStr) && "true".equals(isDeviceStr);

                    String eventType = conditions.get("eventType");
                    boolean isProfile=false;
                    if(!StringUtils.isEmpty(eventType) && "profile".equals(eventType)){
                        isProfile=true;
                    }

                    Map<String, List> result = funnelService.funnelReport(funnel, startDate, endDate, userGroupStr, isList, dimensionStr, account, isDevice,isProfile, Constant.iscache);

                    this.dealReportRateName(result);
                    sb = getExportContent(result);
                }

            } else if (export.getFunctionType().equals(FunctionEnumType.EVENTSTATS.getKey())) {

                //必传参数：eventCondition、startdate、enddate
                String startDate = conditions.get("startdate");
                String endDate = conditions.get("enddate");
                String eventCondition = conditions.get("eventCondition");
                if (StringUtil.isEmpty(eventCondition) || StringUtil.isEmpty(startDate) || StringUtil.isEmpty(endDate)) {

                    logger.info("事件分析下载条件不全：startDate:" + startDate + ", endDate:" + endDate + ", event:" + eventCondition);
                    success = false;

                } else {

                    String groupCondition = conditions.get("dimension");
                    String viewFlag = conditions.get("viewflag");
                    boolean isDevice = Boolean.valueOf(conditions.get("isdevice"));
                    Map<String, List> result = eventStatsService.queryEventStatsData(export.getApp(), account.getId(), startDate, endDate,
                            groupCondition, isDevice, eventCondition, viewFlag);
                    sb = getExportContent(result);
                }

            } else if (FunctionEnumType.COMPLICATED_EVENTS.getKey().equals(export.getFunctionType())) {

                //必传参数：eventCondition、startdate、enddate
                String startDate = conditions.get("startdate");
                String endDate = conditions.get("enddate");
                String eventCondition = conditions.get("eventCondition");
                eventCondition = URLDecoder.decode(eventCondition, StandardCharsets.UTF_8.toString());
                if (StringUtil.isEmpty(eventCondition) || StringUtil.isEmpty(startDate) || StringUtil.isEmpty(endDate)) {

                    logger.info("复杂事件下载条件不全：startDate:" + startDate + ", endDate:" + endDate + ", event:" + eventCondition);
                    success = false;

                } else {

                    String viewFlag = conditions.get("viewflag");
                    Map<String, List> result = complicateEventsService.queryComplicatedEvent(export.getApp(), account.getId(),
                            startDate, endDate, eventCondition, viewFlag, Constant.iscache);
                    sb = getTotalExportContent(result, export.getStartDate(), export.getEndDate());
                    //sb = getExportContent(result);
                }

            } else if (export.getFunctionType().equals(FunctionEnumType.CUSTOMRETENTION.getKey())) {

                //必传参数：eventinfo、startdate、enddate
                String start = conditions.get("startdate");
                String end = conditions.get("enddate");
                String eventInfo = conditions.get("eventinfo");
                String retentiontype = conditions.get("retentiontype");

                if (StringUtil.isEmpty(retentiontype) || ("define".equals(retentiontype) && StringUtil.isEmpty(eventInfo))
                        || StringUtil.isEmpty(start) || StringUtil.isEmpty(end)) {

                    logger.info("自定义留存概览下载条件不全：startDate:" + start + ", endDate:" + end + ", event:" + eventInfo);
                    success = false;

                } else {

                    String isDeviceStr = conditions.get("isdevice");
                    String reportView = conditions.get("reportview");
                    String userGroupStr = conditions.get("usergroupid");
                    String dimensionStr = conditions.get("dimention");
                    boolean isDevice = !StringUtil.isEmpty(isDeviceStr) && "true".equals(isDeviceStr);
                    boolean isList = conditions.get("datatype") != null && "list".equals(conditions.get("datatype"));
                    String type = conditions.get("retentiontype");

                    if (StringUtil.isEmpty(reportView)) {
                        reportView = "day";
                    }

                    int interval = this.getIntervalByViewType(start, end, reportView);

                    String startDate = this.getStartDateByViewType(start, reportView);
                    String endDate = this.getEndDateByViewType(end, reportView);

                    String eventType = conditions.get("eventType");
                    boolean isProfile=false;
                    if(!StringUtils.isEmpty(eventType) && "profile".equals(eventType)){
                        isProfile=true;
                    }

                    Map<String, List> result = retentionService.retentionReport(startDate, endDate, isList, eventInfo, export.getApp(), userGroupStr, dimensionStr, reportView, interval, isDevice, account.getId(),retentiontype,isProfile, Constant.iscache);
                    this.dealRetentionName(result);
                    sb = getExportContent(result);
                }

            } else if (export.getFunctionType().equals(FunctionEnumType.DETAILCUSTOMRETENTION.getKey())) {

                //必传参数：eventinfo、startdate、enddate
                String start = conditions.get("startdate");
                String end = conditions.get("enddate");
                String eventInfo = conditions.get("eventinfo");

                if (StringUtil.isEmpty(eventInfo) || StringUtil.isEmpty(start) || StringUtil.isEmpty(end)) {

                    logger.info("自定义留存明细下载条件不全：startDate:" + start + ", endDate:" + end + ", event:" + eventInfo);
                    success = false;

                } else {

                    String isDeviceStr = conditions.get("isdevice");
                    String reportView = conditions.get("reportview");
                    String userGroupStr = conditions.get("usergroupid");
                    String dimensionStr = conditions.get("dimention");
                    boolean isDevice = !StringUtil.isEmpty(isDeviceStr) && "true".equals(isDeviceStr);
                    boolean isList = conditions.get("datatype") != null && "list".equals(conditions.get("datatype"));
                    String type = conditions.get("retentiontype");

                    if (StringUtil.isEmpty(reportView)) {
                        reportView = "day";
                    }

                    int interval = this.getIntervalByViewType(start, end, reportView);

                    String startDate = this.getStartDateByViewType(start, reportView);
                    String endDate = this.getEndDateByViewType(end, reportView);

                    String eventType = conditions.get("eventType");
                    boolean isProfile=false;
                    if(!StringUtils.isEmpty(eventType) && "profile".equals(eventType)){
                        isProfile=true;
                    }

                    Map<String, List> result = retentionService.retentionDetailReport(account, startDate, endDate, isList, eventInfo,
                            export.getApp(), userGroupStr, dimensionStr, reportView, interval, isDevice,type,isProfile, Constant.iscache);

                    this.dealRetentionName(result);
                    sb = getExportContent(result);
                }

            }

            logger.info(export.getId() + ":" + export.getFileName() + ":\n" + sb.toString());

            //上传到S3服务器
            uploadFileToS3(sb, export.getFileName());

        } catch (Exception e) {
            success = false;
            e.printStackTrace();
            logger.error(e.getMessage());
        }

        //更新导出记录
        if (success) {
            updateStatus(export.getId(), DownloadStatusEnumType.COMPLETE.getCode());
        } else {
            updateStatus(export.getId(), DownloadStatusEnumType.FAILED.getCode());
        }
    }

    /**
     * 根据日周月获取开始时间
     * created by sunhao 20170510
     */
    private String getStartDateByViewType(String startDate, String viewType) {

        String resultStartDate = startDate;

        switch (viewType) {
            case VIEW_TYPE_DAY:
                resultStartDate = startDate;
                break;
            case VIEW_TYPE_WEEK:
                resultStartDate = DateUtil.getFirstDayStrOfWeek(DateUtil.parseDate(startDate));
                break;
            case VIEW_TYPE_MONTH:
                resultStartDate = DateUtil.getFirstDayOfMonth(DateUtil.parseDate(startDate));
                break;
        }

        return resultStartDate;
    }

    /**
     * 根据日周月获取结束时间
     * created by sunhao 20170510
     */
    private String getEndDateByViewType(String endDate, String viewType) {

        String resultEndDate = endDate;

        switch (viewType) {
            case VIEW_TYPE_DAY:
                resultEndDate = endDate;
                break;
            case VIEW_TYPE_WEEK:
                resultEndDate = DateUtil.getLastDayStrOfWeek(DateUtil.parseDate(endDate));
                break;
            case VIEW_TYPE_MONTH:
                resultEndDate = DateUtil.getLastDayOfMonth(DateUtil.parseDate(endDate));
                break;
        }

        return resultEndDate;
    }

    /**
     * 根据日周月获取时间间隔
     * created by sunhao 20170510
     */
    private int getIntervalByViewType(String startDate, String endDate, String viewType) {

        int interval = 0;

        switch (viewType) {
            case VIEW_TYPE_DAY:
                interval = DateUtil.getDateInterval(startDate, endDate).size();
                break;
            case VIEW_TYPE_WEEK:
                interval = DateUtil.getEveryWeek(startDate, endDate).size();
                break;
            case VIEW_TYPE_MONTH:
                interval = DateUtil.getEveryMonth(startDate, endDate).size();
                break;
        }

        return interval;
    }

    private void dealRetentionName(Map<String, List> result) {

        List<String> names = result.get("name");
        List<String> columnKey = result.get("columnkey");
        List<String> newColumnKey = new ArrayList<>();
        List<String> newName = new ArrayList<>();
        for (int i = 0; i < columnKey.size(); i++) {
            if (i > 1) {
                newColumnKey.add(2 * i - 2, columnKey.get(i));
                newName.add(2 * i - 2, names.get(i));
                newColumnKey.add(2 * i - 1, "rate_" + columnKey.get(i));
                newName.add(2 * i - 1, names.get(i) + "留存率");
            } else {
                newColumnKey.add(i, columnKey.get(i));
                newName.add(i, names.get(i));
            }
        }
        result.put("name", newName);
        result.put("columnkey", newColumnKey);
    }

    /**
     * 处理报表中带rate的名字
     * created by sunhao 20170510
     */
    private void dealReportRateName(Map<String, List> result) {

        List<String> name = result.get("name");
        List<String> columnKey = result.get("columnkey");
        List<String> newColumnKey = new ArrayList<>();
        List<String> newName = new ArrayList<>();
        for (int i = 0; i < columnKey.size(); i++) {
            if (i != 0) {
                newColumnKey.add(2 * i - 1, columnKey.get(i));
                newName.add(2 * i - 1, name.get(i));
                newColumnKey.add(2 * i, "rate_" + columnKey.get(i));
                newName.add(2 * i, name.get(i) + "率");
            } else {
                newColumnKey.add(i, columnKey.get(i));
                newName.add(i, name.get(i));
            }
        }
        result.put("name", newName);
        result.put("columnkey", newColumnKey);
    }

    private StringBuffer getExportContent(Map<String, List> result) {
        StringBuffer sb = new StringBuffer();
        List<String> name = result.get("name");
        List<String> columnKey = result.get("columnkey");
        List<Map<String, Object>> value = result.get("val");

        if (!CollectionUtils.isEmpty(name)) {

            sb.append(String.join(",", name)).append("\r\n");
            for (Map<String, Object> v : value) {
                for (int i = 0; i < columnKey.size(); i++) {
                    sb.append(v.get(columnKey.get(i))).append(columnKey.get(i).startsWith("rate_") ? "%" : "")
                            .append(i == columnKey.size() - 1 ? "\r\n" : ",");
                }
            }
        }

        return sb;
    }


    private StringBuffer getTotalExportContent(Map<String, List> result,String startDate,String endDate) {
        StringBuffer sb = new StringBuffer();
        List<String> name = result.get("name");
        List<String> columnKey = result.get("columnkey");
        List<Map<String, Object>> value = result.get("val");
        List<Map<String, Object>> totalValue = result.get("totalval");

        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
        Date parseStartDate=new Date();
        Date parseEndDate=new Date();
        try {
            parseStartDate = sdf2.parse(startDate);
            parseEndDate = sdf2.parse(endDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        String startDate1 = sdf1.format(parseStartDate);
        String endDate1 = sdf1.format(parseEndDate);
        String dateStr=startDate1+"-"+endDate1;

        if (!CollectionUtils.isEmpty(name)) {

            sb.append(String.join(",", name)).append("\r\n");
            sb.append("汇总"+"\r\n");
            for (Map<String, Object> v : totalValue) {
                for (int i = 0; i < columnKey.size(); i++) {
                    if (i == 0) {
                        sb.append(dateStr + ",");
                    } else{
                        sb.append(v.get(columnKey.get(i))).append(columnKey.get(i).startsWith("rate_") ? "%" : "")
                                .append(i == columnKey.size() - 1 ? "\r\n" : ",");
                    }
                }
            }
            sb.append("明细"+"\r\n");
            for (Map<String, Object> v : value) {
                for (int i = 0; i < columnKey.size(); i++) {
                    sb.append(v.get(columnKey.get(i))).append(columnKey.get(i).startsWith("rate_") ? "%" : "")
                            .append(i == columnKey.size() - 1 ? "\r\n" : ",");
                }
            }
        }
        return sb;
    }



    private StringBuffer getExportContent(ReportChartResult reportChartResult) {
        StringBuffer sb = new StringBuffer();
        List<String> column = new ArrayList<>();
        column.addAll(reportChartResult.getColumn());
        column.addAll(reportChartResult.getName());
        List<String> key = reportChartResult.getKey();
        List<Object[]> value = reportChartResult.getVal();

        if (!CollectionUtils.isEmpty(column)) {

            sb.append(String.join(",", column)).append("\r\n");

            for (int i = 0; i < key.size(); i++) {
                sb.append(key.get(i)).append(",");
                for (int j = 0; j < value.size(); j++) {
                    sb.append(value.get(j)[i]).append(j == value.size() - 1 ? "\r\n" : ",");
                }
            }
        }

        return sb;
    }

    private void updateStatus(Long id, String status) {
        exportService.updateStatus(id, status);
    }

    /**
     * 上传文件到S3
     * created by sunhao 20170509
     */
    private void uploadFileToS3(StringBuffer fileContent, String fileName) throws IOException {

        final String s3key = DOWNLOAD_PATH + fileName;

        //删除重复文件
        if (AwsS3Util.getInstance().getAmazonS3().doesObjectExist(S3_DOWNLOAD_BUCKET, s3key)) {
            AwsS3Util.getInstance().deleteS3Object(S3_DOWNLOAD_BUCKET, s3key);
        }

        //上传文件
        if (fileContent != null) {

            //fileContent无数据
            if (fileContent.capacity() == 0) {
                fileContent.append("-无记录-");
            }

            AwsS3Util.getInstance().uploadStringToS3(S3_DOWNLOAD_BUCKET, s3key, fileContent.toString());
        }
    }
}
