package com.ktg.iscs.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ktg.common.core.domain.entity.SysDictData;
import com.ktg.common.utils.DictUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.iscs.domain.IsMaterials;
import com.ktg.iscs.domain.IsMaterialsCabinet;
import com.ktg.iscs.domain.IsMaterialsLoanException;
import com.ktg.iscs.domain.IsMaterialsType;
import com.ktg.iscs.domain.vo.homePage.HomePageLoanVO;
import com.ktg.iscs.domain.vo.homePage.HomePageVO;
import com.ktg.iscs.domain.vo.homePage.OngoingJobVO;
import com.ktg.iscs.domain.vo.statistics.*;
import com.ktg.iscs.mapper.StatisticsMapper;
import com.ktg.iscs.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 统计接口
 *
 * @author cgj
 * @date 2024-10-16
 */
@Slf4j
@Service
public class StatisticsApiServiceImpl implements StatisticsApiService {

    @Autowired
    private StatisticsMapper statisticsMapper;
    @Autowired
    private IIsMaterialsService iIsMaterialsService;
    @Autowired
    private IIsMaterialsTypeService iIsMaterialsTypeService;
    @Autowired
    private IIsMaterialsCabinetService iIsMaterialsCabinetService;
    @Autowired
    private IIsMaterialsLoanExceptionService isMaterialsLoanExceptionService;

    @Override
    public List<CabinetStatisticsVO> getCabinetStatistics(String startTime, String endTime) {
        return statisticsMapper.getCabinetStatistics(startTime, endTime);
    }

    @Override
    public List<MaterialsStatusStatisticsVO> getMaterialsStatusStatistics(String startTime, String endTime) {
        return statisticsMapper.getMaterialsStatusStatistics(startTime, endTime);
    }

    @Override
    public List<MaterialsLoanStatisticsVO> getMaterialsLoanStatistics(String startTime, String endTime) {
        List<MaterialsLoanStatisticsVO> list = statisticsMapper.getMaterialsLoanStatistics(startTime, endTime);
        return list;
    }

    @Override
    public List<MaterialsChangeStatisticsVO> getMaterialsChangeStatistics(String startTime, String endTime) {
        return statisticsMapper.getMaterialsChangeStatistics(startTime, endTime);
    }

    @Override
    public List<UserLoanStatisticsVO> getUserLoanStatistics(String startTime, String endTime) {
        return statisticsMapper.getUserLoanStatistics(startTime, endTime);
    }

    @Override
    public List<DayLoanStatisticsVO> getDayLoanStatistics(String startTime, String endTime) {
        return statisticsMapper.getDayLoanStatistics(startTime, endTime);
    }

    @Override
    public HomePageVO getHomePage(String startTime, String endTime) {
        // 1.第一部分
        List<IsMaterials> materialsList = iIsMaterialsService.list(Wrappers.<IsMaterials>lambdaQuery().isNotNull(IsMaterials::getMaterialsCabinetId));
        // 1.1物资总数
        int materialsCount = materialsList.size();
        // 1.2柜中物资
        int cabinetMaterialsCount = (int) materialsList.stream().filter(o -> "1".equals(o.getLoanState())).count();
        // 1.3借出物资
        int loanMaterialsCount = (int) materialsList.stream().filter(o -> "0".equals(o.getLoanState())).count();
        // 1.4异常数量
        int exceptionMaterialsCount = (int) isMaterialsLoanExceptionService.count(Wrappers.<IsMaterialsLoanException>lambdaQuery().eq(IsMaterialsLoanException::getStatus, "0"));

        // 2.第二部分，进行中的作业
        List<OngoingJobVO> ongoingJobList = statisticsMapper.getOngoingJobList();

        // 3.第三部分
        List<HomePageLoanVO> loanList = statisticsMapper.getLoanList(startTime, endTime);

        HomePageVO vo = new HomePageVO();
        vo.setMaterialsCount(materialsCount);
        vo.setCabinetMaterialsCount(cabinetMaterialsCount);
        vo.setLoanMaterialsCount(loanMaterialsCount);
        vo.setExceptionMaterialsCount(exceptionMaterialsCount);
        vo.setJobList(ongoingJobList);
        vo.setLoanList(loanList);
        return vo;
    }

    @Override
    public List<InventoryVO> getMaterialInventory(Integer type) {
        Assert.notNull(type, "type不能为空！");
        // 1.获取所有在柜子中的物资
        List<IsMaterials> allMaterials = iIsMaterialsService.list(Wrappers.<IsMaterials>lambdaQuery()
                .isNotNull(IsMaterials::getMaterialsCabinetId)
                .ne(IsMaterials::getMaterialsCabinetId, 0));
        // 2.获取所有的柜子
        List<IsMaterialsCabinet> cabinets = iIsMaterialsCabinetService.list();
        // 2.1获取物资分类
        List<IsMaterialsType> materialsTypes = iIsMaterialsTypeService.list();
        // 3.构建返回类
        List<InventoryVO> inventoryVOS = new ArrayList<>();
        if (!allMaterials.isEmpty() && !cabinets.isEmpty() && !materialsTypes.isEmpty()) {
            for (IsMaterialsCabinet cabinet : cabinets) {
                InventoryVO inventoryVO = new InventoryVO();
                inventoryVO.setCabinetId(cabinet.getCabinetId());
                inventoryVO.setCabinetName(cabinet.getCabinetName());

                List<MaterialsTypeVO> materialsTypeVOS = new ArrayList<>();
                for (IsMaterialsType materialsType : materialsTypes) {
                    MaterialsTypeVO materialsTypeVO = new MaterialsTypeVO();
                    materialsTypeVO.setMaterialsTypeId(materialsType.getMaterialsTypeId());
                    materialsTypeVO.setMaterialsTypeName(materialsType.getMaterialsTypeName());
                    materialsTypeVO.setMaterialsTypeIcon(materialsType.getMaterialsTypeIcon());
                    materialsTypeVO.setMaterialsTypePicture(materialsType.getMaterialsTypePicture());
                    materialsTypeVOS.add(materialsTypeVO);
                }

                inventoryVO.setMaterialsTypeVOList(materialsTypeVOS);
                inventoryVOS.add(inventoryVO);
            }
            // 4.获取每个类型下需要解析的数据
            List<IsMaterials> materials = new ArrayList<>();
            if (type.equals(0)) {
                // 总览
                materials = allMaterials;
            }
            if (type.equals(1)) {
                // 柜中
                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "1".equals(o.getLoanState())).collect(Collectors.toList());
            }
            if (type.equals(2)) {
                // 借出
                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "0".equals(o.getLoanState())).collect(Collectors.toList());
            }
            if (type.equals(3)) {
                // 正常
                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "0".equals(o.getStatus())).collect(Collectors.toList());
            }
            if (type.equals(4)) {
                // 过期
                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "2".equals(o.getStatus())).collect(Collectors.toList());
            }
            if (type.equals(5)) {
                // 损坏
                materials = allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "1".equals(o.getStatus())).collect(Collectors.toList());
            }
            // 5.开始解析
            if (!materials.isEmpty()) {
                for (InventoryVO inventoryVO : inventoryVOS) {
                    List<IsMaterials> cabinetMaterials = materials.stream().filter(o -> o.getMaterialsCabinetId().equals(inventoryVO.getCabinetId())).collect(Collectors.toList());
                    if (!cabinetMaterials.isEmpty()) {
                        for (MaterialsTypeVO isMaterialsType : inventoryVO.getMaterialsTypeVOList()) {
                            int number = (int) cabinetMaterials.stream().filter(o -> o.getMaterialsTypeId().equals(isMaterialsType.getMaterialsTypeId())).count();
                            isMaterialsType.setNumber(number);
                        }
                    }
                }
            }
        }
        return inventoryVOS;
    }

    @Override
    public List<InventoryTypeVO> getInventorySum() {
        List<SysDictData> inventoryType = DictUtils.getDictCache("Inventory_type");
        List<IsMaterials> allMaterials = iIsMaterialsService.list(Wrappers.<IsMaterials>lambdaQuery()
                .isNotNull(IsMaterials::getMaterialsCabinetId)
                .ne(IsMaterials::getMaterialsCabinetId, 0));
        ArrayList<InventoryTypeVO> inventoryTypeVOS = new ArrayList<>();
        for (SysDictData sysDictData : inventoryType) {
            InventoryTypeVO inventoryTypeVO = new InventoryTypeVO();
            inventoryTypeVO.setDictValue(sysDictData.getDictValue());
            inventoryTypeVO.setDictLabel(sysDictData.getDictLabel());
            int sum = 0;
            if ("0".equals(sysDictData.getDictValue())) {
                // 总览
                sum = allMaterials.size();
            }
            if ("1".equals(sysDictData.getDictValue())) {
                // 柜中
                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "1".equals(o.getLoanState())).count();
            }
            if ("2".equals(sysDictData.getDictValue())) {
                // 借出
                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getLoanState()) && "0".equals(o.getLoanState())).count();
            }
            if ("3".equals(sysDictData.getDictValue())) {
                // 正常
                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "0".equals(o.getStatus())).count();
            }
            if ("4".equals(sysDictData.getDictValue())) {
                // 过期
                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "2".equals(o.getStatus())).count();
            }
            if ("5".equals(sysDictData.getDictValue())) {
                // 损坏
                sum = (int) allMaterials.stream().filter(o -> StringUtils.isNotBlank(o.getStatus()) && "1".equals(o.getStatus())).count();
            }
            inventoryTypeVO.setSum(sum);
            inventoryTypeVOS.add(inventoryTypeVO);
        }
        return inventoryTypeVOS;
    }

    @Override
    public void exportMaterialInventory(HttpServletResponse response, HttpServletRequest request) {
        String fileName = "导出数据";
        List<InventoryVO> materialInventory0 = getMaterialInventory(0);
        List<InventoryVO> materialInventory1 = getMaterialInventory(1);
        List<InventoryVO> materialInventory2 = getMaterialInventory(2);
        List<InventoryVO> materialInventory3 = getMaterialInventory(3);
        List<InventoryVO> materialInventory4 = getMaterialInventory(4);
        List<InventoryVO> materialInventory5 = getMaterialInventory(5);


        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
        getData(workbook, materialInventory0, "总览");
        getData(workbook, materialInventory1, "柜中");
        getData(workbook, materialInventory2, "借出");
        getData(workbook, materialInventory3, "正常");
        getData(workbook, materialInventory4, "过期");
        getData(workbook, materialInventory5, "损坏");
        fileOutputStream(request, response, workbook, fileName);
    }


    // 使用synchronized，防止list在多线程的情况下顺序变乱
    private synchronized void getData(SXSSFWorkbook workbook, List<InventoryVO> data, String sheetName) {
        // 由于数据格式的问题，直接转换成List<List<String>>
        // 数据承载
        ArrayList<List<String>> lists = new ArrayList<>();
        // 构造第一行
        List<String> strings = new ArrayList<>();
        strings.add(0, "物资类型");
        for (InventoryVO datum : data) {
            strings.add(datum.getCabinetName());
        }
        lists.add(strings);
        // 获取接下来还有几行
        List<MaterialsTypeVO> materialsTypeVOList = data.get(0).getMaterialsTypeVOList();
        if (!materialsTypeVOList.isEmpty()) {
            // 每一个typeNames代表一行数据
            List<String> typeNames = materialsTypeVOList.stream().map(MaterialsTypeVO::getMaterialsTypeName).collect(Collectors.toList());
            // 开始组装接下来的每一行数据
            for (String typeName : typeNames) {
                // 构造其他行
                List<String> strings1 = new ArrayList<>();
                strings1.add(typeName);
                for (InventoryVO datum : data) {
                    // 只会有一条
                    List<MaterialsTypeVO> collect = datum.getMaterialsTypeVOList().stream().filter(o -> o.getMaterialsTypeName().equals(typeName)).collect(Collectors.toList());
                    strings1.add((collect.get(0).getNumber() == null || collect.get(0).getNumber() == 0) ? "" : String.valueOf(collect.get(0).getNumber()));
                }
                lists.add(strings1);
            }
        }
        SXSSFSheet sheet = workbook.createSheet(sheetName);
        for (int i = 0; i < lists.size(); i++) {
            sheet.setColumnWidth(i, 5000);
            SXSSFRow row = sheet.createRow(i);
            for (int j = 0; j < lists.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists.get(i).get(j));
            }
        }
    }

    private void fileOutputStream(HttpServletRequest request, HttpServletResponse response, SXSSFWorkbook workbook, String fileName) {
        OutputStream output = null;
        try {
            output = response.getOutputStream();
            String agent = request.getHeader("USER-AGENT").toLowerCase();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // 使用正确的 MIME 类型
            response.setContentType("application/force-download");
            response.setContentType("application/vnd.ms-excel");
            String codedFileName = URLEncoder.encode(fileName, "UTF-8");
            if (agent.contains("firefox")) {
                response.setCharacterEncoding("utf-8");
                response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(), StandardCharsets.UTF_8) + ".xlsx");
            } else {
                response.setHeader("content-disposition", "attachment;filename=" + codedFileName + ".xlsx");
            }
            workbook.write(output);
        } catch (IOException e) {
            log.error("数据导出出错:{}", e.getMessage());
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    System.out.println("关闭输出流时出错: " + e.getMessage());
                }
            }
        }
    }

    @Override
    public void exportBaseData(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
        String fileName = "导出数据";
        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
        // ------------------------ 第一个sheet---------------------------------------------
        List<CabinetStatisticsVO> cabinetStatisticsVOList = getCabinetStatistics(startTime, endTime);
        // 数据承载
        ArrayList<List<String>> lists = new ArrayList<>();
        // 构造第一行
        List<String> one = new ArrayList<>();
        one.add("物资柜");
        one.add("开关次数");
        one.add("异常总数");
        one.add("错放数");
        one.add("超时未关");
        lists.add(one);
        // 构造其他行
        for (CabinetStatisticsVO vo : cabinetStatisticsVOList) {
            List<String> other = new ArrayList<>();
            other.add(vo.getCabinetName());
            other.add(vo.getOpenCount() == null ? "0" : String.valueOf(vo.getOpenCount()));
            other.add(String.valueOf(vo.getMisplaceCount() + vo.getOpenTimeoutCount()));
            other.add(String.valueOf(vo.getMisplaceCount()));
            other.add(String.valueOf(vo.getOpenTimeoutCount()));
            lists.add(other);
        }
        SXSSFSheet sheet = workbook.createSheet("物资柜统计");
        for (int i = 0; i < lists.size(); i++) {
            sheet.setColumnWidth(i, 5000);
            SXSSFRow row = sheet.createRow(i);
            for (int j = 0; j < lists.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists.get(i).get(j));
            }
        }
        // ------------------------ 第二个sheet---------------------------------------------
        List<MaterialsStatusStatisticsVO> materialsStatusStatistics = getMaterialsStatusStatistics(startTime, endTime);
        // 数据承载
        ArrayList<List<String>> lists1 = new ArrayList<>();
        // 构造第一行
        List<String> one1 = new ArrayList<>();
        one1.add("物资");
        one1.add("即将过期");
        one1.add("已过期");
        one1.add("损坏数");
        lists1.add(one1);
        // 构造其他行
        for (MaterialsStatusStatisticsVO vo : materialsStatusStatistics) {
            List<String> other = new ArrayList<>();
            other.add(vo.getMaterialsTypeName());
            other.add(String.valueOf(vo.getWillExpireCount()));
            other.add(String.valueOf(vo.getExpiredCount()));
            other.add(String.valueOf(vo.getBadCount()));
            lists1.add(other);
        }
        SXSSFSheet sheet1 = workbook.createSheet("物资统计");
        for (int i = 0; i < lists1.size(); i++) {
            sheet1.setColumnWidth(i, 5000);
            SXSSFRow row = sheet1.createRow(i);
            for (int j = 0; j < lists1.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists1.get(i).get(j));
            }
        }
        // ------------------------ 第三个sheet---------------------------------------------
        List<MaterialsChangeStatisticsVO> materialsChangeStatistics = getMaterialsChangeStatistics(startTime, endTime);
        // 数据承载
        ArrayList<List<String>> lists2 = new ArrayList<>();
        // 构造第一行
        List<String> one2 = new ArrayList<>();
        one2.add("物资");
        one2.add("正常更换次数");
        one2.add("过期更换次数");
        one2.add("损坏更换次数");
        lists2.add(one2);
        // 构造其他行
        for (MaterialsChangeStatisticsVO vo : materialsChangeStatistics) {
            List<String> other = new ArrayList<>();
            other.add(vo.getMaterialsTypeName());
            other.add(String.valueOf(vo.getAllCount()));
            other.add(String.valueOf(vo.getExpireCount()));
            other.add(String.valueOf(vo.getBadCount()));
            lists2.add(other);
        }
        SXSSFSheet sheet2 = workbook.createSheet("物资更换统计");
        for (int i = 0; i < lists2.size(); i++) {
            sheet2.setColumnWidth(i, 5000);
            SXSSFRow row = sheet2.createRow(i);
            for (int j = 0; j < lists2.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists2.get(i).get(j));
            }
        }
        fileOutputStream(request, response, workbook, fileName);
    }

    @Override
    public void exportClaimAndReturn(HttpServletResponse response, HttpServletRequest request, String startTime, String endTime) {
        String fileName = "导出数据";
        SXSSFWorkbook workbook = new SXSSFWorkbook(20000);
        // ------------------------ 第一个sheet---------------------------------------------
        List<MaterialsLoanStatisticsVO> materialsLoanStatistics = getMaterialsLoanStatistics(startTime, endTime);
        // 数据承载
        ArrayList<List<String>> lists = new ArrayList<>();
        // 构造第一行
        List<String> one = new ArrayList<>();
        one.add("物资");
        one.add("借出平均时长(小时)");
        one.add("领取次数");
        one.add("正常归还次数");
        one.add("超时归还次数");
        lists.add(one);
        // 构造其他行
        for (MaterialsLoanStatisticsVO vo : materialsLoanStatistics) {
            List<String> other = new ArrayList<>();
            other.add(vo.getMaterialsTypeName());
            double seconds = vo.getAverageTime();
            // 计算小时数，并保留两位小数
            double hours = seconds / 3600.0;
            other.add(String.format("%.2f", hours));
            other.add(String.valueOf(vo.getAllCount()));
            other.add(String.valueOf(vo.getReturnCount()));
            other.add(String.valueOf(vo.getTimeoutCount()));
            lists.add(other);
        }
        SXSSFSheet sheet = workbook.createSheet("物资领取归还");
        for (int i = 0; i < lists.size(); i++) {
            sheet.setColumnWidth(i, 5000);
            SXSSFRow row = sheet.createRow(i);
            for (int j = 0; j < lists.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists.get(i).get(j));
            }
        }

        // ------------------------ 第二个sheet---------------------------------------------
        List<DayLoanStatisticsVO> dayLoanStatistics = getDayLoanStatistics(startTime, endTime);
        // 数据承载
        ArrayList<List<String>> lists1 = new ArrayList<>();
        // 构造第一行
        List<String> one1 = new ArrayList<>();
        one1.add("日期");
        one1.add("累计领取次数");
        one1.add("累计正常归还次数");
        one1.add("累计超时归还次数");
        lists1.add(one1);
        // 构造其他行
        for (DayLoanStatisticsVO vo : dayLoanStatistics) {
            List<String> other = new ArrayList<>();
            other.add(vo.getDay());
            other.add(String.valueOf(vo.getAllCount()));
            other.add(String.valueOf(vo.getReturnCount()));
            other.add(String.valueOf(vo.getTimeoutCount()));
            lists1.add(other);
        }
        SXSSFSheet sheet1 = workbook.createSheet("每日领取归还");
        for (int i = 0; i < lists1.size(); i++) {
            sheet1.setColumnWidth(i, 5000);
            SXSSFRow row = sheet1.createRow(i);
            for (int j = 0; j < lists1.get(i).size(); j++) {
                row.createCell(j).setCellValue(lists1.get(i).get(j));
            }
        }
        fileOutputStream(request, response, workbook, fileName);
    }


}
