package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.common.encrypt.DESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.RequestContext;
import com.bocloud.ims.entity.common.Column;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Vpc;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.resource.ExtFileDownLoadService;
import com.bocloud.ims.interfaces.resource.SubnetService;
import com.bocloud.ims.interfaces.resource.VpcService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VpcRepository;
import com.google.common.collect.Maps;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service("extFileDownLoadService")
public class ExtFileDownLoadServiceImpl implements ExtFileDownLoadService {

    private static final Logger logger = LoggerFactory.getLogger(FileDownloadServiceImpl.class);
    @Autowired
    private CloudServerService cloudServerService;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private VpcService vpcService;
    @Autowired
    private SubnetService subnetService;
    @Autowired
    private SubnetRepository subnetRepository;
    private Encryptor encryptor = new DESEncrptor();
    private static ThreadLocal<Integer> row = new ThreadLocal<>();
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Override
    public BocloudResult<Map<String, Object>> vmDownload(Pager pager, String condition, List<Column> columns, RequestContext context, String action) {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        try {
            SXSSFSheet sheet = workbook.createSheet("sheet");
            sheet.setRandomAccessWindowSize(-1);
            // 样式一，标题数据蓝色填充
            CellStyle style = workbook.createCellStyle();
            style.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style.setBorderBottom(BorderStyle.THIN); // 下边框
            style.setBorderLeft(BorderStyle.THIN);// 左边框
            style.setBorderTop(BorderStyle.THIN);// 上边框
            style.setBorderRight(BorderStyle.THIN);// 右边框
            style.setAlignment(HorizontalAlignment.CENTER);
            // 样式二，内容样式
            CellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setBorderTop(BorderStyle.THIN);// 上边框
            cellStyle.setBorderBottom(BorderStyle.THIN); // 下边框
            cellStyle.setBorderLeft(BorderStyle.THIN);// 左边框
            cellStyle.setBorderRight(BorderStyle.THIN);// 右边框
            cellStyle.setAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
            cellStyle.setVerticalAlignment(VerticalAlignment.TOP);// 垂直对齐方式
            // 标题写入
            createVmReport(sheet, style, columns);
            // 读写数据
            Integer total = null;
            switch (action) {
                case "vm":
                    total = cloudServerRepository.count(pager.getParams());
                    break;
                case "vpc":
                    total = vpcRepository.count(pager.getParams());
                    break;
                case "subnet":
                    total = subnetRepository.count(pager.getParams(),null);
                    break;
            }
            // 每个线程处理的数量
            int numbers = 50;
            if (total < numbers) {
                excelExporter(sheet, cellStyle, 1, new Pager(1, numbers, pager.getParams(), pager.getSorter()), context,
                        columns, action);
            } else {
                int pages = total / numbers;
                int lastNumers = total % numbers;
                int rowNumber = 1;
                List<Future<Boolean>> futures = new ArrayList<>();
                for (int i = 1; i <= pages; i++) {
                    int page = i;
                    int finalRowNumber = rowNumber;
                    futures.add(taskExecutor.submit(() -> excelExporter(sheet, cellStyle, finalRowNumber,
                            new Pager(page, numbers, pager.getParams(), pager.getSorter()), context, columns, action)));
                    rowNumber += numbers;
                }
                // 获取结果
                for (Future<Boolean> future : futures) {
                    Boolean successful = future.get(1, TimeUnit.MINUTES);
                    if (successful) {
                        // 收到写入完成提示
                        continue;
                    }
                }
                // 整页数据的异步查询写入完成，处理最后一页不足整页的数据
                if (0 != lastNumers) {
                    excelExporter(sheet, cellStyle, pages * numbers + 1,
                            new Pager(pages + 1, numbers, pager.getParams(), pager.getSorter()), context, columns, action);
                }
            }
            String fileName = "虚拟机统计数据";
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            byte[] ba = byteArrayOutputStream.toByteArray();
            Map<String, Object> resultMap = Maps.newHashMap();
            resultMap.put("fileName", fileName + System.currentTimeMillis() + ".xlsx");
            resultMap.put("data", Base64.getEncoder().encodeToString(ba));
            return new BocloudResult<>(true, resultMap, "下载成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage(), e);
            return new BocloudResult<>(false, e.getMessage());
        } finally {
            if (null != workbook) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    logger.error("error message：", e);
                }
            }
        }
    }

    /**
     * 根据选中字段创建标题
     *
     * @param sheet
     * @param style
     * @param columns
     */
    public void createVmReport(SXSSFSheet sheet, CellStyle style, List<Column> columns) {
        int number = -1;
        SXSSFRow row = sheet.createRow(0);
        for (Column column: columns) {
            number++;
            row.createCell(number).setCellValue(column.getName());
            sheet.getRow(0).getCell(number).setCellStyle(style);
            sheet.setColumnWidth(number,30 * 256);
            sheet.addMergedRegion(new CellRangeAddress(0,1,number,number));
        }
    }

    /**
     * excel导出选中字段信息
     *
     * @param sheet
     * @param cellStyle
     * @param rowNumber
     * @param pager
     * @param context
     * @param columns
     * @return boolean
     */
    public Boolean excelExporter(SXSSFSheet sheet, CellStyle cellStyle, int rowNumber, Pager pager,
                                 RequestContext context, List<Column> columns, String action) {
        int number = rowNumber;
        String methodName = null;
        try {
            BocloudResult result = null;
            //定义正则匹配规则
            String regex = "\\$\\{(\\w+)\\}";
            Pattern pattern = Pattern.compile(regex);
            //根据action查询具体类型的资源
            switch (action) {
                case "vm":
                    result = cloudServerService.list(pager, context);
                    if (result.isFailed()) {
                        logger.error("获取" + action + "数据失败", result.getMessage());
                        return false;
                    }
                    List<CloudServer> servers = JSONObject.parseObject(JSON.toJSONString(result.getData())).getJSONArray("rows")
                            .toJavaList(CloudServer.class);
                    for (CloudServer server : servers) {
                        int columnNum = -1;
                        if (null != server.getIsTemplate() && server.getIsTemplate()) {
                            continue;
                        }
                        row.set(number += 1);
                        // 创建数据初始化行
                        SXSSFRow sheetRow = sheet.createRow(row.get());
                        for (Column column : columns) {
                            columnNum++;
                            HashMap<String,String> data = new HashMap<>();
                            Matcher matcher = pattern.matcher(column.getValue());
                            boolean isMatched = false;
                            while(matcher.find()) {
                                isMatched = true;
                                data.put(matcher.group(0),getMethodName(matcher.group(1)));
                            }
                            if(!isMatched) {
                                methodName = getMethodName(column.getValue());
                                try {
                                    //通过value值调用getter() Method
                                    Class clazz = server.getClass();
                                    Method method = clazz.getMethod(methodName);
                                    sheetRow.createCell(columnNum).setCellValue(String.valueOf(method.invoke(server)));
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                            else {
                                try {
                                    Method method;
                                    String replace = column.getValue();
                                    for (String s : data.keySet()) {
                                        Class clazz = server.getClass();
                                        method = clazz.getMethod(data.get(s));
                                        replace = replace.replace(s,String.valueOf(method.invoke(server)));
                                    }
                                    sheetRow.createCell(columnNum).setCellValue(replace);
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                        }
                    }
                    break;
                case "vpc":
                    result = vpcService.list(pager,context);
                    if (result.isFailed()) {
                        logger.error("获取" + action + "数据失败", result.getMessage());
                        return false;
                    }
                    List<Vpc> vpcs = JSONObject.parseObject(JSON.toJSONString(result.getData())).getJSONArray("rows")
                            .toJavaList(Vpc.class);
                    for (Vpc vpc : vpcs) {
                        int columnNum = -1;
                        row.set(number += 1);
                        // 创建数据初始化行
                        SXSSFRow sheetRow = sheet.createRow(row.get());
                        for (Column column : columns) {
                            columnNum++;
                            HashMap<String,String> data = new HashMap<>();
                            Matcher matcher = pattern.matcher(column.getValue());
                            boolean isMatched = false;
                            while(matcher.find()) {
                                isMatched = true;
                                data.put(matcher.group(0),getMethodName(matcher.group(1)));
                            }
                            if(!isMatched) {
                                methodName = getMethodName(column.getValue());
                                try {
                                    //通过value值调用getter() Method
                                    Class clazz = vpc.getClass();
                                    Method method = clazz.getMethod(methodName);
                                    sheetRow.createCell(columnNum).setCellValue(String.valueOf(method.invoke(vpc)));
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                            else {
                                try {
                                    Method method;
                                    String replace = column.getValue();
                                    for (String s : data.keySet()) {
                                        Class clazz = vpc.getClass();
                                        method = clazz.getMethod(data.get(s));
                                        replace = replace.replace(s,String.valueOf(method.invoke(vpc)));
                                    }
                                    sheetRow.createCell(columnNum).setCellValue(replace);
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                        }
                    }
                    break;
                case "subnet":
                    result = subnetService.list(pager);
                    if (result.isFailed()) {
                        logger.error("获取" + action + "数据失败", result.getMessage());
                        return false;
                    }
                    List<Subnet> subnets = JSONObject.parseObject(JSON.toJSONString(result.getData())).getJSONArray("rows")
                            .toJavaList(Subnet.class);
                    for (Subnet subnet : subnets) {
                        int columnNum = -1;
                        row.set(number += 1);
                        // 创建数据初始化行
                        SXSSFRow sheetRow = sheet.createRow(row.get());
                        for (Column column : columns) {
                            columnNum++;
                            HashMap<String,String> data = new HashMap<>();
                            Matcher matcher = pattern.matcher(column.getValue());
                            boolean isMatched = false;
                            while(matcher.find()) {
                                isMatched = true;
                                data.put(matcher.group(0),getMethodName(matcher.group(1)));
                            }
                            if(!isMatched) {
                                methodName = getMethodName(column.getValue());
                                try {
                                    //通过value值调用getter() Method
                                    Class clazz = subnet.getClass();
                                    Method method = clazz.getMethod(methodName);
                                    sheetRow.createCell(columnNum).setCellValue(String.valueOf(method.invoke(subnet)));
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                            else {
                                try {
                                    Method method;
                                    String replace = column.getValue();
                                    for (String s : data.keySet()) {
                                        Class clazz = subnet.getClass();
                                        method = clazz.getMethod(data.get(s));
                                        replace = replace.replace(s,String.valueOf(method.invoke(subnet)));
                                    }
                                    sheetRow.createCell(columnNum).setCellValue(replace);
                                    sheet.getRow(row.get()).getCell(columnNum).setCellStyle(cellStyle);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    return false;
                                }
                            }
                        }
                    }
                    break;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    public String getMethodName(String valueName) {
        char[] chars = valueName.toCharArray();
        if(chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] -= 32;
        }
        String methodName = "get" + String.valueOf(chars);
        return methodName;
    }
}
