package com.jjt.biz.controller;

import com.jjt.biz.domain.TwinDevice;
import com.jjt.biz.service.ITwinDeviceService;
import com.jjt.biz.vo.StopDetailVO;
import com.jjt.calc.domain.TwinCalcStop;
import com.jjt.calc.service.ITwinCalcStopService;
import com.jjt.common.constant.CacheConstants;
import com.jjt.common.core.controller.BaseController;
import com.jjt.common.core.redis.RedisCache;
import com.jjt.common.utils.DateUtils;
import com.jjt.common.utils.StringUtils;
import com.jjt.utils.Tools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.ParseException;
import java.time.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * Excel导出控制类
 *
 * @author ruoyi
 */
@Api(tags = "数据导出接口--停机")
@RestController
@Slf4j
public class ApiStopExportController extends BaseController {
    @Resource
    private ITwinCalcStopService stopService;
    @Resource
    private ITwinDeviceService deviceService;
    @Resource
    private RedisCache redisCache;

    @ApiOperation("导出停机数据")
    @RequestMapping("/api/export/stops")
    @CrossOrigin(origins = "*")
    public void stopsExport(String start, String end, HttpServletResponse response) throws ParseException {
        Date sTime = DateUtils.parseDate(start, DateUtils.YYYY_MM_DD_HH_MM_SS);
        Date eTime = DateUtils.parseDate(end, DateUtils.YYYY_MM_DD_HH_MM_SS);
        List<TwinCalcStop> list = stopService.selectTwinCalcStopListByDate(sTime, eTime);
        Map<Integer, List<TwinCalcStop>> stopDeviceGroup = list.stream().collect(Collectors.groupingBy(TwinCalcStop::getStopType, LinkedHashMap::new, Collectors.toList()));
        //1停经片停机，2-CCD停机(相机号+断纱/故障)，3-人工停机，4-断电停机，5-设备故障停机，6-落布米数达到停机，7-盘头剩余圈数达到停机
        String[] stopStr = {"停经片停机", "CCD停机(相机号+断纱/故障)", "人工停机", "断电停机", "设备故障停机", "落布米数达到停机", "盘头剩余圈数达到停机"};
        //停机次数
        Integer[] stopNum = new Integer[7];
        int totalNum = 0;
        //停机时间
        Long[] stopTime = new Long[7];
        Arrays.fill(stopTime, 0L);
        AtomicReference<Long> totalTime = new AtomicReference<>(0L);
        Map<Long, TwinDevice> deviceMap = deviceService.deviceMap();
        for (Map.Entry<Integer, List<TwinCalcStop>> entry : stopDeviceGroup.entrySet()) {
            Integer stopType = entry.getKey();
            int pos = stopType - 1;
            List<TwinCalcStop> stops = entry.getValue();
            stopNum[pos] = stops.size();
            totalNum += stops.size();
            stops.forEach(stop -> {
                long t = (stop.getEndTime().getTime() - stop.getStartTime().getTime()) / 1000;
                stopTime[pos] += t;
                totalTime.updateAndGet(v -> v + t);
            });
        }
        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/stops.xlsx"); Workbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
            CreationHelper creationHelper = wb.getCreationHelper();
            CellStyle percentStyle = wb.createCellStyle();
            percentStyle.setDataFormat(creationHelper.createDataFormat().getFormat("0.00%"));
            CellStyle timeStyle = wb.createCellStyle();
            timeStyle.setDataFormat(creationHelper.createDataFormat().getFormat(DateUtils.YYYY_MM_DD_HH_MM_SS));
            CellStyle rightStyle = wb.createCellStyle();
            rightStyle.setAlignment(HorizontalAlignment.RIGHT);
            Sheet sheetAt = wb.getSheetAt(0);
            Row title = sheetAt.getRow(0);
            Cell cell = title.getCell(0);
            cell.setCellValue("停机原因分析（" + start + "至" + end + "）");
            for (int i = 0; i < stopStr.length; i++) {
                Row row = sheetAt.createRow(i + 2);
                Cell[] cells = new Cell[5];
                for (int j = 0; j < cells.length; j++) {
                    cells[j] = row.createCell(j);
                }
                cells[0].setCellValue(stopStr[i]);
                cells[1].setCellValue(stopNum[i]);
                cells[2].setCellValue(Tools.convertHMS(stopTime[i]));
                cells[2].setCellStyle(rightStyle);
                float percentNum = BigDecimal.valueOf(stopNum[i]).divide(BigDecimal.valueOf(totalNum), 4, RoundingMode.HALF_UP).floatValue();
                float percentTimes = BigDecimal.valueOf(stopTime[i]).divide(BigDecimal.valueOf(totalTime.get()), 4, RoundingMode.HALF_UP).floatValue();
                cells[3].setCellValue(percentNum);
                cells[3].setCellStyle(percentStyle);
                cells[4].setCellValue(percentTimes);
                cells[4].setCellStyle(percentStyle);
            }

            Sheet sheet = wb.getSheetAt(1);
            AtomicInteger rowNum = new AtomicInteger(1);
            list.forEach(stop -> {
                Row row = sheet.createRow(rowNum.get());
                Cell[] cells = new Cell[5];
                for (int j = 0; j < cells.length; j++) {
                    cells[j] = row.createCell(j);
                }

                cells[0].setCellValue(deviceMap.get(stop.getDeviceId()).getDeviceName());
                cells[1].setCellValue(stopStr[stop.getStopType() - 1]);
                cells[2].setCellValue(stop.getStartTime());
                cells[2].setCellStyle(timeStyle);
                cells[3].setCellValue(stop.getEndTime());
                cells[3].setCellStyle(timeStyle);
                Duration duration = Duration.between(stop.getStartTime().toInstant(), stop.getEndTime().toInstant());
                cells[4].setCellValue(Tools.convertHMS(duration.getSeconds()));
                cells[4].setCellStyle(rightStyle);
                rowNum.getAndIncrement();
            });

            // 清空response
            response.reset();
            // 设置response的Header
            response.setCharacterEncoding("UTF-8");
            //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
            //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
            // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("停机分析" + DateUtils.dateTimeNow() + ".xlsx", "UTF-8"));
            response.setContentType("application/octet-stream");
            wb.write(outputStream);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @ApiOperation("导出当前停机明细")
    @RequestMapping("/api/export/stop")
    @CrossOrigin(origins = "*")
    public void stopExport(HttpServletResponse response) throws ParseException {
        String[] stopStr = {"", "停经片停机", "断纱停机", "人工停机", "断电停机", "设备故障停机", "落布米数达到停机", "叫料停机"};
        TwinDevice searchDevice = new TwinDevice();
        searchDevice.setOnline("1");
        List<TwinDevice> deviceList = deviceService.selectTwinDeviceList(searchDevice);
        Object d = redisCache.getCacheObject(CacheConstants.STOP_DETAIL);
        if (d != null) {
            List<StopDetailVO> stopList = (List<StopDetailVO>) d;
            stopList.sort(Comparator.comparing(StopDetailVO::getDeviceId));
            int[] nums = new int[7];
            String[] devices = new String[7];
            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/stopDetail.xlsx"); Workbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
                CellStyle p2 = wb.createCellStyle();
                p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
                Sheet sheet2 = wb.getSheetAt(1);
                int rowNum = 2;
                for (StopDetailVO vo : stopList) {
                    if (!vo.getHasData()) {
                        combo(6, nums, devices, vo.getDeviceId());
                        continue;
                    }
//                    if (vo.getSpeed() > 0) {
//                        combo(0, nums, devices, vo.getDeviceId());
//                        if (vo.getStop() != 0) {
//                            combo(8, nums, devices, vo.getDeviceId());
//                        }
//                    }
                    if (vo.getSpeed() > 0f || vo.getStop() == 0) {
                        combo(0, nums, devices, vo.getDeviceId());
                    } else {
                        switch (vo.getStop()) {
                            case 0:
//                            combo(9, nums, devices, vo.getDeviceId());
//                            if (vo.getSpeed() == 0f) {
//                                combo(7, nums, devices, vo.getDeviceId());
//                            }
                                break;
                            case 1:
                                combo(1, nums, devices, vo.getDeviceId());
                                break;
                            case 2:
                                combo(2, nums, devices, vo.getDeviceId());
                                break;
                            case 6:
                                combo(3, nums, devices, vo.getDeviceId());
                                break;
                            case 7:
                                combo(4, nums, devices, vo.getDeviceId());
                                break;
                            default:
                                combo(5, nums, devices, vo.getDeviceId());
                        }
                    }


                    Row row = sheet2.createRow(rowNum++);
                    Cell[] cells = new Cell[4];
                    for (int j = 0; j < cells.length; j++) {
                        cells[j] = row.createCell(j);
                    }
                    cells[0].setCellValue(vo.getDeviceId());
                    cells[1].setCellValue(vo.getSpeed());
                    cells[1].setCellStyle(p2);
                    cells[2].setCellValue(vo.getStop());
                    cells[3].setCellValue(stopStr[vo.getStop()]);
                }
                Sheet sheet1 = wb.getSheetAt(0);
                Cell cell = sheet1.getRow(2).getCell(2);
                cell.setCellValue(deviceList.size());

                cell = sheet1.getRow(3).getCell(2);
                cell.setCellValue(nums[0]);
                cell = sheet1.getRow(3).getCell(4);
                cell.setCellValue(devices[0]);

                cell = sheet1.getRow(4).getCell(2);
                cell.setCellValue(nums[1]);
                cell = sheet1.getRow(4).getCell(4);
                cell.setCellValue(devices[1]);

                cell = sheet1.getRow(5).getCell(2);
                cell.setCellValue(nums[2]);
                cell = sheet1.getRow(5).getCell(4);
                cell.setCellValue(devices[2]);

                cell = sheet1.getRow(6).getCell(2);
                cell.setCellValue(nums[3]);
                cell = sheet1.getRow(6).getCell(4);
                cell.setCellValue(devices[3]);

                cell = sheet1.getRow(7).getCell(2);
                cell.setCellValue(nums[4]);
                cell = sheet1.getRow(7).getCell(4);
                cell.setCellValue(devices[4]);

                cell = sheet1.getRow(8).getCell(2);
                cell.setCellValue(nums[5]);
                cell = sheet1.getRow(8).getCell(4);
                cell.setCellValue(devices[5]);

                cell = sheet1.getRow(9).getCell(2);
                cell.setCellValue(nums[6]);
                cell = sheet1.getRow(9).getCell(4);
                cell.setCellValue(devices[6]);

//                cell = sheet1.getRow(14).getCell(2);
//                cell.setCellValue(nums[7]);
//                cell = sheet1.getRow(14).getCell(4);
//                cell.setCellValue(devices[7]);
//
//                cell = sheet1.getRow(15).getCell(2);
//                cell.setCellValue(nums[8]);
//                cell = sheet1.getRow(15).getCell(4);
//                cell.setCellValue(devices[8]);
//
//                cell = sheet1.getRow(16).getCell(2);
//                cell.setCellValue(nums[9]);
//                cell = sheet1.getRow(16).getCell(4);
//                cell.setCellValue(devices[9]);
                // 清空response
                response.reset();
                // 设置response的Header
                response.setCharacterEncoding("UTF-8");
                //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
                //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
                // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("停机明细" + DateUtils.dateTimeNow() + ".xlsx", "UTF-8"));
                response.setContentType("application/octet-stream");
                wb.write(outputStream);
                outputStream.flush();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 组装设备ID
     */
    private void combo(int i, int[] nums, String[] devices, long id) {
        nums[i]++;
        if (StringUtils.isNotEmpty(devices[i])) {
            devices[i] += ",";
        } else {
            devices[i] = "";
        }
        devices[i] += id;
    }

    @ApiOperation("停机分类并发导出")
    @RequestMapping("/api/export/stops/type/{type}")
    @CrossOrigin(origins = "*")
    public void stopsTypeExport(@PathVariable Integer type, String start, String end, Integer st, Integer et, HttpServletResponse response) {
        LocalDate s = LocalDate.parse(start);
        LocalDate e = LocalDate.parse(end);
        List<TwinCalcStop> list = new ArrayList<>();
        do {
            LocalDateTime ldtS = LocalDateTime.of(s, LocalTime.MIN).plusHours(st);
            LocalDateTime ldtE = LocalDateTime.of(s, LocalTime.MIN).plusHours(et);
            Date date = Date.from(ldtS.toLocalDate().atStartOfDay(ZoneOffset.of("+8")).toInstant());
            Date sTime = Date.from(ldtS.atZone(ZoneId.systemDefault()).toInstant());
            Date eTime = Date.from(ldtE.atZone(ZoneId.systemDefault()).toInstant());
            List<TwinCalcStop> stopList = stopService.selectTwinCalcStopListByDate(sTime, eTime);
            stopList.forEach(stop -> {
                stop.setDataDate(date);
            });
            list.addAll(stopList);
            s = s.plusDays(1);
        } while (!s.isAfter(e));

        List<TwinCalcStop> stopList = list.stream().filter(stop -> stop.getStopType().equals(type)).collect(Collectors.toList());
        Map<Long, TwinDevice> deviceMap = deviceService.deviceMap();
        Map<Date, List<TwinCalcStop>> stopDateGroup = stopList.stream().collect(Collectors.groupingBy(TwinCalcStop::getDataDate, LinkedHashMap::new, Collectors.toList()));
        //1停经片停机，2-CCD停机(相机号+断纱/故障)，3-人工停机，4-断电停机，5-设备故障停机，6-落布米数达到停机，7-盘头剩余圈数达到停机
        String[] stopStr = {"断纱", "断纱", "人工停机", "断电停机", "设备故障停机", "下卷", "叫料"};

        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/stopsType.xlsx"); Workbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
            CreationHelper creationHelper = wb.getCreationHelper();
            CellStyle percentStyle = wb.createCellStyle();
            percentStyle.setDataFormat(creationHelper.createDataFormat().getFormat("0.00%"));
            CellStyle timeStyle = wb.createCellStyle();
            timeStyle.setDataFormat(creationHelper.createDataFormat().getFormat(DateUtils.YYYY_MM_DD_HH_MM_SS));
            CellStyle dateStyle = wb.createCellStyle();
            dateStyle.setDataFormat(creationHelper.createDataFormat().getFormat(DateUtils.YYYY_MM_DD));
            CellStyle p2 = wb.createCellStyle();
            p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
            Sheet sheetAt = wb.getSheetAt(0);
            int rowNum = 1;
            AtomicInteger rs = new AtomicInteger(1);
            for (Map.Entry<Date, List<TwinCalcStop>> entry : stopDateGroup.entrySet()) {
                List<TwinCalcStop> stops = entry.getValue();
                Row row = sheetAt.createRow(rowNum);
                Cell[] cells = new Cell[7];
                for (int j = 0; j < cells.length; j++) {
                    cells[j] = row.createCell(j);
                }
                cells[0].setCellValue(entry.getKey());
                cells[0].setCellStyle(dateStyle);
                cells[1].setCellValue(st + "-" + et);
                Map<Long, List<TwinCalcStop>> stopDeviceGroup = stops.stream().collect(Collectors.groupingBy(TwinCalcStop::getDeviceId, LinkedHashMap::new, Collectors.toList()));
                cells[2].setCellValue(stopDeviceGroup.size());
                int num = stops.size();
                cells[3].setCellValue(num);
                //0.最小，1.最大,2.总时间
                final long[] time = {999999L, 0, 0};
                Sheet sheet = wb.getSheetAt(1);
                stops.forEach(stop -> {
                    long t = (stop.getEndTime().getTime() - stop.getStartTime().getTime()) / 1000;
                    if (t < time[0]) {
                        time[0] = t;
                    }
                    if (t > time[1]) {
                        time[1] = t;
                    }
                    time[2] += t;

                    Row r1 = sheet.createRow(rs.get());
                    Cell[] cs = new Cell[6];
                    for (int j = 0; j < cs.length; j++) {
                        cs[j] = r1.createCell(j);
                    }
                    cs[0].setCellValue(entry.getKey());
                    cs[0].setCellStyle(dateStyle);
                    cs[1].setCellValue(st + "-" + et);
                    cs[2].setCellValue(deviceMap.get(stop.getDeviceId()).getDeviceName());
                    cs[3].setCellValue(stopStr[stop.getStopType() - 1]);
                    cs[4].setCellValue(stop.getStartTime());
                    cs[4].setCellStyle(timeStyle);
                    cs[5].setCellValue(stop.getEndTime());
                    cs[5].setCellStyle(timeStyle);
                    rs.getAndIncrement();
                });

                cells[4].setCellValue(time[1]);
                cells[5].setCellValue(time[0]);
                float avg = BigDecimal.valueOf(time[2]).divide(BigDecimal.valueOf(num), 2, RoundingMode.HALF_UP).floatValue();
                cells[6].setCellValue(avg);
                cells[6].setCellStyle(p2);
                rowNum++;
            }

            // 清空response
            response.reset();
            // 设置response的Header
            response.setCharacterEncoding("UTF-8");
            //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
            //attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
            // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("并发" + stopStr[type - 1] + "分析" + DateUtils.dateTimeNow() + ".xlsx", "UTF-8"));
            response.setContentType("application/octet-stream");
            wb.write(outputStream);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}
