package com.jjt.biz.controller;

import com.jjt.biz.service.impl.BrokenYarnExportServiceImpl;
import com.jjt.biz.vo.FormulaDetail;
import com.jjt.biz.vo.YarnVO;
import com.jjt.calc.domain.TwinCalcDay;
import com.jjt.calc.service.ITwinCalcDayService;
import com.jjt.common.constant.CacheConstants;
import com.jjt.common.core.controller.BaseController;
import com.jjt.common.core.domain.R;
import com.jjt.common.core.redis.RedisCache;
import com.jjt.common.utils.DateUtils;
import com.jjt.common.utils.bean.BeanUtils;
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.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.BarDirection;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
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.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * Excel导出控制类
 *
 * @author ruoyi
 */
@Api(tags = "数据导出接口--纱线")
@RestController
@Slf4j
public class ApiYarnExportController extends BaseController {
    @Resource
    private ITwinCalcDayService twinCalcDayService;
    @Resource
    private BrokenYarnExportServiceImpl brokenYarnExportService;

    @Resource
    private RedisCache redisCache;

    @ApiOperation("纱线规格")
    @RequestMapping("/api/export/yarn-specifications")
    @CrossOrigin(origins = "*")
    public void yarnSpecificationsExport(Integer day, HttpServletResponse response) {
        List<FormulaDetail> list = redisCache.getCacheObject(CacheConstants.INDEX_FORMULA_DETAIL);
        if (list != null) {
            list.sort(Comparator.comparing(FormulaDetail::getFormula_data_4).thenComparing(FormulaDetail::getFormula_data_5).thenComparing(FormulaDetail::getFormula_data_6)
                    .thenComparing(FormulaDetail::getFormula_data_7).thenComparing(FormulaDetail::getFormula_data_8).thenComparing(FormulaDetail::getFormula_data_9)
                    .thenComparing(FormulaDetail::getFormula_data_15));
            Map<String, List<FormulaDetail>> map = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnD, LinkedHashMap::new, Collectors.toList()));
            LocalDateTime localDateTime = LocalDateTime.now();
            if (localDateTime.getHour() < 7) {
                //当天7点前，则是前天数据
                localDateTime = localDateTime.minusDays(2);
            } else {
                //7点后，就是昨日数据
                localDateTime = localDateTime.minusDays(1);
            }
            LocalDate localDate = localDateTime.toLocalDate();
            Date sd = Date.from(localDate.atStartOfDay(ZoneOffset.of("+8")).toInstant());
            List<TwinCalcDay> calcDayList = twinCalcDayService.selectTwinCalcDayListByTime(sd, sd);
            Map<Long, BigDecimal> decimalMap = calcDayList.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, TwinCalcDay::getLength));
            try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/yarn.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
                Sheet sheet = wb.getSheetAt(0);
                AtomicInteger rowNum = new AtomicInteger(2);
                CellStyle percentStyle = wb.createCellStyle();
                percentStyle.setDataFormat(wb.createDataFormat().getFormat("0.00%"));
                // 垂直居中
                percentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                CellStyle p2 = wb.createCellStyle();
                p2.setDataFormat(wb.createDataFormat().getFormat("0.00"));
                for (String s : map.keySet()) {
                    int sr = rowNum.get();
                    List<FormulaDetail> fList = map.get(s);
                    for (FormulaDetail detail : fList) {
                        Row row = sheet.createRow(rowNum.get());
                        Cell[] cells = new Cell[39];
                        for (int i = 0; i < cells.length; i++) {
                            cells[i] = row.createCell(i);
                        }
                        detail.setYarnCells(cells, p2);
                        rowNum.getAndIncrement();
                    }
                    if (fList.size() > 1) {
                        int er = sr + fList.size() - 1;
                        sheet.addMergedRegion(new CellRangeAddress(sr, er, 0, 0));
                        sheet.addMergedRegion(new CellRangeAddress(sr, er, 1, 1));
                        sheet.addMergedRegion(new CellRangeAddress(sr, er, 2, 2));
                    }
                }
                XSSFSheet sheet2 = wb.getSheetAt(1);
                wb.setSheetName(1, "未来产能预期（" + day + "天）");
                AtomicInteger rn = new AtomicInteger(2);
                //1.先按底纱分组
                Map<String, List<FormulaDetail>> map2 = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnDd, LinkedHashMap::new, Collectors.toList()));
                for (String s : map2.keySet()) {
                    int sr = rn.get();
                    List<FormulaDetail> l12list = map2.get(s);
                    //2.再按规格分组
                    Map<Integer, List<FormulaDetail>> d1map = l12list.stream().collect(Collectors.groupingBy(FormulaDetail::getFormula_data_6, LinkedHashMap::new, Collectors.toList()));
                    for (Integer l3d : d1map.keySet()) {
                        int ssr = rn.get();
                        List<FormulaDetail> l3list = d1map.get(l3d);
                        //3.再按盘头根数和毛高分组
                        Map<String, List<FormulaDetail>> d2map = l3list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnPt, LinkedHashMap::new, Collectors.toList()));
                        for (String pt : d2map.keySet()) {
                            List<FormulaDetail> ptList = d2map.get(pt);
                            FormulaDetail detail = ptList.get(0);
                            String device = "";
                            BigDecimal length = BigDecimal.ZERO;
                            for (FormulaDetail dd : ptList) {
                                BigDecimal temp = decimalMap.get(dd.getDeviceId());
                                if (temp != null) {
                                    length = length.add(temp);
                                }
//                                device += dd.getDevice() + "/";
                            }
                            BigDecimal yLength = length.multiply(BigDecimal.valueOf(day));
                            Row row = sheet2.createRow(rn.get());
                            Cell[] cells = new Cell[12];
                            for (int i = 0; i < cells.length; i++) {
                                cells[i] = row.createCell(i);
                            }
                            cells[0].setCellValue(rn.get() - 1);
                            cells[1].setCellValue(detail.getFormula_data_4());
                            cells[2].setCellValue(detail.getFormula_data_5());
                            cells[3].setCellValue(detail.getFormula_data_6());
                            cells[4].setCellValue(detail.getFormula_data_10());
                            cells[5].setCellValue(detail.getFormula_data_11());
                            cells[6].setCellValue(detail.getFormula_data_12());
                            cells[7].setCellValue(detail.getFormula_data_15());
                            cells[8].setCellValue(length.doubleValue());
                            cells[8].setCellStyle(p2);
                            cells[9].setCellValue(yLength.doubleValue());
                            cells[9].setCellStyle(p2);
                            //规格占比
                            BigDecimal percent1 = BigDecimal.valueOf(ptList.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
                            cells[10].setCellValue(percent1.doubleValue());
                            cells[10].setCellStyle(percentStyle);
                            //底纱占比
                            BigDecimal percent2 = BigDecimal.valueOf(l12list.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
                            cells[11].setCellValue(percent2.doubleValue());
                            cells[11].setCellStyle(percentStyle);
                            rn.getAndIncrement();
                        }
                        if (d2map.size() > 1) {
                            int er = rn.get() - 1;
                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 1, 1));
                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 2, 2));
                            sheet2.addMergedRegion(new CellRangeAddress(ssr, er, 3, 3));
                        }
                    }
                    if (d1map.size() > 1) {
                        int er = rn.get() - 1;
                        sheet2.addMergedRegion(new CellRangeAddress(sr, er, 11, 11));
                    }
                }
                int endRn = rn.get() - 1;
                int[] pos = {13, 1, 20, endRn + 1};
                int[] xdata = {2, endRn, 0, 0};
                int[] data = {2, endRn, 10, 10};
                brokenYarnExportService.drawBar(sheet2, "规格占比", "规格序号", pos, xdata, data, BarDirection.COL);
                // 清空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/view/yarn-specifications")
    @CrossOrigin(origins = "*")
    public R yarnSpecificationsView(@RequestParam Integer day) {
        List<FormulaDetail> list = redisCache.getCacheObject(CacheConstants.INDEX_FORMULA_DETAIL);
        Map<String, Object> result = new HashMap<>(16);
        if (list != null) {
            list.sort(Comparator.comparing(FormulaDetail::getFormula_data_4).thenComparing(FormulaDetail::getFormula_data_5).thenComparing(FormulaDetail::getFormula_data_6)
                    .thenComparing(FormulaDetail::getFormula_data_7).thenComparing(FormulaDetail::getFormula_data_8).thenComparing(FormulaDetail::getFormula_data_9)
                    .thenComparing(FormulaDetail::getFormula_data_15));
            Map<String, List<FormulaDetail>> map = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnD, LinkedHashMap::new, Collectors.toList()));
            result.put("list", map);
            LocalDate localDate = LocalDateTime.now().minusHours(7).minusDays(1).toLocalDate();
            Date sd = DateUtils.toDate(localDate);
            List<TwinCalcDay> calcDayList = twinCalcDayService.selectTwinCalcDayListByTime(sd, sd);
            Map<Long, BigDecimal> decimalMap = calcDayList.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, TwinCalcDay::getLength));
            List<YarnVO> voList = new ArrayList<>();
            //1.先按底纱分组
            Map<String, List<FormulaDetail>> map2 = list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnDd, LinkedHashMap::new, Collectors.toList()));
            for (String s : map2.keySet()) {
                List<FormulaDetail> l12list = map2.get(s);
                //2.再按规格分组
                Map<Integer, List<FormulaDetail>> d1map = l12list.stream().collect(Collectors.groupingBy(FormulaDetail::getFormula_data_6, LinkedHashMap::new, Collectors.toList()));
                for (Integer l3d : d1map.keySet()) {
                    List<FormulaDetail> l3list = d1map.get(l3d);
                    //3.再按盘头根数和毛高分组
                    Map<String, List<FormulaDetail>> d2map = l3list.stream().collect(Collectors.groupingBy(FormulaDetail::getYarnPt, LinkedHashMap::new, Collectors.toList()));
                    for (String pt : d2map.keySet()) {
                        List<FormulaDetail> ptList = d2map.get(pt);
                        FormulaDetail detail = ptList.get(0);
                        YarnVO vo = new YarnVO();
                        BeanUtils.copyProperties(detail, vo);
                        BigDecimal length = BigDecimal.ZERO;
                        for (FormulaDetail dd : ptList) {
                            BigDecimal temp = decimalMap.get(dd.getDeviceId());
                            if (temp != null) {
                                length = length.add(temp);
                            }
                        }
                        BigDecimal yLength = length.multiply(BigDecimal.valueOf(day));
                        vo.setLastLength(length);
                        vo.setNextLength(yLength);
                        //规格占比
                        BigDecimal percent1 = BigDecimal.valueOf(ptList.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
                        vo.setPercentD(percent1);
                        BigDecimal percent2 = BigDecimal.valueOf(l12list.size()).divide(BigDecimal.valueOf(list.size()), 4, RoundingMode.HALF_UP);
                        vo.setPercentDd(percent2);
                        voList.add(vo);
                    }
                }
            }
            result.put("calc", voList);
            return R.ok(result);
        }
        return R.fail("暂时没有数据");
    }

    @ApiOperation("导出断纱分析")
    @RequestMapping("/api/export/broken-yarn")
    @CrossOrigin(origins = "*")
    public void brokenYarnExport(String date, HttpServletResponse response) throws ParseException {
        LocalDate localDate = LocalDate.parse(date);
        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("tpl/brokenYarn.xlsx"); XSSFWorkbook wb = new XSSFWorkbook(inputStream); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
            //1.基本信息表
            brokenYarnExportService.base(wb, localDate);
            //2.停机原因分析
            brokenYarnExportService.stop(wb, localDate);
            //4.断纱停机TOP排名
            brokenYarnExportService.top(wb, localDate);
            // 清空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("断纱分析日报" + localDate + ".xlsx", "UTF-8"));
            response.setContentType("application/octet-stream");
            wb.write(outputStream);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
