package com.repair.controller;


import com.repair.api.RepairConsumeControllerAPI;
import com.repair.common.utils.ExcelExportUtil;
import com.repair.common.utils.ExcelUtils;
import com.repair.common.utils.TimeExchange;
import com.repair.common.utils.paramUtils;
import com.repair.model.enumModel.eFileType;
import com.repair.model.pojo.RepairArticleType;
import com.repair.model.pojo.RepairConsume;
import com.repair.model.request.insertRepairAssociationRequest;
import com.repair.model.request.insertRepairConsumeRequest;
import com.repair.model.request.updateRepairConsumeRequest;
import com.repair.model.result.CommonResult;
import com.repair.model.result.PageUtils;
import com.repair.model.vo.*;
import com.repair.services.RepairAreaService;
import com.repair.services.RepairArticleTypeService;
import com.repair.services.RepairConsumeService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author ceshi
 * @since 2023-07-18
 */
@RestController
public class RepairConsumeController implements RepairConsumeControllerAPI {

    @Autowired
    private RepairAreaService repairAreaService;
    @Autowired
    private RepairConsumeService repairConsumeService;
    @Autowired
    private RepairArticleTypeService repairArticleTypeService;

    /**
     * 关联耗材中添加耗材
     * @param irc 耗材数据
     * @param bindingResult 是否为空判断
     * @return
     */
    @Override
    public CommonResult InsertRepairAssociation(insertRepairAssociationRequest irc, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairConsume data = repairConsumeService.queryConsumeByName(irc.getName(), irc.getSchoolId());
        if (data != null) {
            return CommonResult.fail("该报修耗材已存在！");
        }

        RepairConsume rc = new RepairConsume()
                .setName(irc.getName())
                .setSchoolId(irc.getSchoolId())
                .setArticleId(irc.getArticleId())
                .setPrice(new BigDecimal(0));

        int result = repairConsumeService.insertRepairConsume(rc);

        return result > 0 ? CommonResult.ok("添加成功") : CommonResult.fail("添加失败");
    }

    /**
     * 新增耗材数据
     * @param ircr 耗材数据
     * @param bindingResult 是否为空判断
     * @return
     */
    @Override
    public CommonResult InsertRepairConsume(insertRepairConsumeRequest ircr, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairConsume data = repairConsumeService.queryConsumeByName(ircr.getName(), ircr.getSchoolId());
        if (data != null) {
            return CommonResult.fail("该报修耗材已存在！");
        }

        RepairConsume rc = new RepairConsume()
                .setName(ircr.getName())
                .setSchoolId(ircr.getSchoolId())
                .setArticleId(StringUtils.join(ircr.getArticleIds(), ','))
                .setPrice(ircr.getPrice())
                .setContent(ircr.getContent());

        int result = repairConsumeService.insertRepairConsume(rc);

        return result > 0 ? CommonResult.ok("添加成功") : CommonResult.fail("添加失败");
    }

    /**
     * 根据数据ID修改耗材数据
     * @param urcr 耗材数据
     * @param bindingResult 是否为空判断
     * @return
     */
    @Override
    public CommonResult updateRepairConsumeById(updateRepairConsumeRequest urcr, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairConsume data = repairConsumeService.queryConsumeByName(urcr.getName(), urcr.getSchoolId());
        if (data != null && !data.getId().equals(urcr.getId())) {
            return CommonResult.fail("该报修耗材已存在！");
        }

        RepairConsume rc = new RepairConsume()
                .setId(urcr.getId())
                .setSchoolId(urcr.getSchoolId())
                .setName(urcr.getName())
                .setArticleId(StringUtils.join(urcr.getArticleIds(), ','))
                .setPrice(urcr.getPrice())
                .setContent(urcr.getContent());

        int result = repairConsumeService.updateRepairConsume(rc);

        return result > 0 ? CommonResult.ok("修改成功") : CommonResult.fail("修改失败");
    }

    /**
     * 耗材管理分页数据查询
     * @param currentPage 当前页数
     * @param pageCount 一页数据条数
     * @param name 耗材名称
     * @param startTime 起始时间
     * @param endTime 结束时间
     * @return
     */
    @Override
    public CommonResult queryPageRepairConsumes(int currentPage, int pageCount, String name, String startTime, String endTime) {

        if (startTime != null && endTime != null) {
            try {
                startTime = TimeExchange.getStartOfDayStr(TimeExchange.StringToDate(startTime, "yyyy-MM-dd"));
                endTime = TimeExchange.getEndOfDayStr(TimeExchange.StringToDate(endTime, "yyyy-MM-dd"));
            } catch (Exception e) {
            }
        }

        PageUtils<RepairConsumeVo> result = repairConsumeService.queryPageRepairConsumes(currentPage, pageCount, name, startTime, endTime);

        for (RepairConsumeVo r : result.getList()) {
            if (r.getArticleId() != null) {
                r.setArticleIds(Arrays.asList(r.getArticleId().split(",")));
            }
            if (r.getArticleName() != null) {
                r.setArticleNames(Arrays.asList(r.getArticleName().split(",")));
            }
        }

        return CommonResult.ok(result);

    }

    /**
     * 根据数据ID删除耗材数据
     * @param id 数据ID
     * @return
     */
    @Override
    public CommonResult deleteRepairConsumeById(int id) {
        RepairConsume data = repairConsumeService.getRepairById(id);
        if (data == null) {
            return CommonResult.fail("当前数据不存在，删除失败！");
        }

        int result = repairConsumeService.deleteRepairConsumeById(id);

        return result > 0 ? CommonResult.ok("删除成功") : CommonResult.fail("删除失败");
    }

    /**
     * 耗材数据导出
     * @param name 耗材名称
     * @param startTime 起始时间
     * @param endTime 结束时间
     * @param response 文件响应流
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    @Override
    public void downloadRepairConsumeExcel(String name, String startTime, String endTime, HttpServletResponse response) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Map<String, String> map = new HashMap<>();
        //表头与键值对的映射关系
        map.put("id", "数据ID");
        map.put("name", "耗材名称");
        map.put("schoolName", "校区名称");
        map.put("price", "耗材单价");
        map.put("artileName", "物品类型");
        map.put("entryName", "录入人员");
        map.put("updateTimeStr", "录入时间");

        if (startTime != null && endTime != null) {
            try {
                startTime = TimeExchange.getStartOfDayStr(TimeExchange.StringToDate(startTime, "yyyy-MM-dd"));
                endTime = TimeExchange.getEndOfDayStr(TimeExchange.StringToDate(endTime, "yyyy-MM-dd"));
            } catch (Exception e) {
            }
        }
        List<ConsumeVo> datas = repairConsumeService.queryConsumeList(name, startTime, endTime);

        List<String> orderList = new ArrayList<>();
        orderList.add("id");
        orderList.add("name");
        orderList.add("schoolName");
        orderList.add("price");
        orderList.add("artileName");
        orderList.add("entryName");
        orderList.add("updateTimeStr");

        //导出逻辑 这里的list是从导入里面哪来的 map1与map不一样 orderList这里为空
        Workbook workbook = ExcelExportUtil.createWorkbook(datas, map, 1, "耗材管理表", orderList);

        ExcelUtils.excelDownload(workbook, "耗材管理.xlsx", response);
    }

    /**
     * 耗材模板数据导出
     * @param response 文件响应流
     */
    @Override
    public void downloadRepairConsumeModelExcel(HttpServletResponse response) {
        ExcelUtils.fileDownload("/耗材管理模板.xlsx", response);
    }

    /**
     * 耗材数据导入
     * @param file 导入文件
     * @return
     * @throws IOException
     */
    @Override
    public CommonResult importRepairConsumeExcel(MultipartFile file) throws IOException {
        if (file.isEmpty() || file.getSize() == 0) {
            return CommonResult.fail("导入文件不能为空");
        }
        String ContentType = file.getContentType();
        InputStream inputStream = file.getInputStream();
        List<RepairConsume> result = new ArrayList<>();

        //xls格式文件
        if (ContentType.equals(eFileType.Xls.getValue())) {

            CommonResult<List<RepairConsume>> resultData = readXls(inputStream);
            if (!resultData.isSuccess()) {
                return resultData;
            }
            result = resultData.getData();

        } else if (ContentType.equals(eFileType.Xlsx.getValue())) {
            CommonResult<List<RepairConsume>> resultData = readXlsx(inputStream);
            if (!resultData.isSuccess()) {
                return resultData;
            }
            result = resultData.getData();

        } else {
            return CommonResult.fail("耗材数据导入只支持Xls、Xlsx");
        }

        boolean resultBool = repairConsumeService.saveBatch(result);

        return resultBool ? CommonResult.ok("导入成功") : CommonResult.fail("导入失败");
    }

    /**
     * 导入Xls文件方法
     * @param inputStream
     * @return
     * @throws IOException
     */
    private CommonResult<List<RepairConsume>> readXls(InputStream inputStream) throws IOException {
        HSSFWorkbook sheets = new HSSFWorkbook(inputStream);
        List<RepairConsume> result = new ArrayList<>();
        List<String> ConsumeNames = new ArrayList<>();
        //读取第一张sheet
        HSSFSheet sheetAt = sheets.getSheetAt(0);

        //获取校区数据
        List<RepairSchoolVo> schools = repairAreaService.queryRepairSchools();
        //报修物品
        List<RepairArticleType> articles = repairArticleTypeService.getRepairArticleTypes();
        //耗材数据
        List<RepairConsume> consumes = repairConsumeService.getConsumes();

        DataFormatter dataFormatter = new DataFormatter();

        try {
            //sheetAt.getLastRowNum()：从0开始统计数量 所以得+1
            for (int rowNum = 1; rowNum < sheetAt.getLastRowNum() + 1; rowNum++) {

                HSSFRow row = sheetAt.getRow(rowNum);

                if (rowNum == 1) {
                    String name = dataFormatter.formatCellValue(row.getCell(0));//耗材名称
                    if (!name.equals("名称")) {
                        return CommonResult.fail("导入数据第一列为名称");
                    }
                    String schoolName = dataFormatter.formatCellValue(row.getCell(1));//校区名称
                    if (!schoolName.equals("校区")) {
                        return CommonResult.fail("导入数据第二列为校区");
                    }
                    String ArticleName = dataFormatter.formatCellValue(row.getCell(2));//报修物品类别
                    if (!ArticleName.equals("类别")) {
                        return CommonResult.fail("导入数据第三列为类别");
                    }
                    String price = dataFormatter.formatCellValue(row.getCell(3));//耗材单价
                    if (!price.equals("价格（元）")) {
                        return CommonResult.fail("导入数据第四列为价格");
                    }

                } else {
                    RepairConsume data = new RepairConsume();
                    //耗材名称
                    String name = dataFormatter.formatCellValue(row.getCell(0));
                    ConsumeNames.add(name);
                    if (ConsumeNames.stream().distinct().count() != ConsumeNames.size()) {
                        return CommonResult.fail("导入的Excel中" + name + "存在重复数据");
                    }
                    data.setName(name);
                    //校区
                    String schoolName = dataFormatter.formatCellValue(row.getCell(1));
                    Optional<RepairSchoolVo> school = schools.stream().filter(e -> e.getName().equals(schoolName)).findFirst();
                    if (school != null && school.isPresent()) {
                        data.setSchoolId(school.get().getId());
                    } else {
                        return CommonResult.fail(name + "的" + schoolName + "校区数据在数据库中不存在");
                    }

                    //重复数据提示
                    long exist = consumes.stream().filter(e -> e.getSchoolId().equals(school.get().getId()) && e.getName().equals(name)).count();
                    if (exist > 0) {
                        return CommonResult.fail(schoolName + "的" + name + "耗材数据在系统中已存在，请勿重复导入");
                    }

                    //报修物品（类别）
                    String article = dataFormatter.formatCellValue(row.getCell(2));
                    String[] articleStrs = null;
                    if (article.contains("、")) {
                        articleStrs = article.split("、");
                    } else if (article.contains(",")) {
                        articleStrs = article.split(",");
                    } else {
                        articleStrs = new String[1];
                        articleStrs[0] = article;
                    }
                    List<String> ass = new ArrayList<>();
                    for (String as : articleStrs) {
                        if (!as.equals("")) {
                            Optional<RepairArticleType> shiftData = articles.stream().filter(e -> e.getName().equals(as) && data.getSchoolId().equals(e.getSchoolId())).findFirst();
                            if (shiftData != null && shiftData.isPresent()) {
                                ass.add(shiftData.get().getId().toString());
                            } else {
                                return CommonResult.fail(name + "的" + as + "数据不存在");
                            }
                        }
                        data.setArticleId(StringUtils.join(ass, ','));
                        result.add(data);
                    }

                    //价格
                    BigDecimal price = new BigDecimal(String.valueOf(row.getCell(3))).stripTrailingZeros();
                    data.setPrice(price);
                }
            }
        } catch (Exception e) {
            return CommonResult.fail("请按模板格式导入数据");
        }

        return CommonResult.ok(result);
    }

    /**
     * 导入Xlsx文件方法
     * @param inputStream
     * @return
     * @throws IOException
     */
    private CommonResult<List<RepairConsume>> readXlsx(InputStream inputStream) throws IOException {
        XSSFWorkbook sheets = new XSSFWorkbook(inputStream);
        List<RepairConsume> result = new ArrayList<>();
        List<String> ConsumeNames = new ArrayList<>();
        //读取第一张sheet
        XSSFSheet sheetAt = sheets.getSheetAt(0);

        //获取校区数据
        List<RepairSchoolVo> schools = repairAreaService.queryRepairSchools();
        //报修物品
        List<RepairArticleType> articles = repairArticleTypeService.getRepairArticleTypes();
        //耗材数据
        List<RepairConsume> consumes = repairConsumeService.getConsumes();

        DataFormatter dataFormatter = new DataFormatter();

        try {
            //sheetAt.getLastRowNum()：从0开始统计数量 所以得+1
            for (int rowNum = 1; rowNum < sheetAt.getLastRowNum() + 1; rowNum++) {

                XSSFRow row = sheetAt.getRow(rowNum);

                if (rowNum == 1) {
                    String name = dataFormatter.formatCellValue(row.getCell(0));//耗材名称
                    if (!name.equals("名称")) {
                        return CommonResult.fail("导入数据第一列为名称");
                    }
                    String schoolName = dataFormatter.formatCellValue(row.getCell(1));//校区名称
                    if (!schoolName.equals("校区")) {
                        return CommonResult.fail("导入数据第二列为校区");
                    }
                    String ArticleName = dataFormatter.formatCellValue(row.getCell(2));//报修物品类别
                    if (!ArticleName.equals("类别")) {
                        return CommonResult.fail("导入数据第三列为类别");
                    }
                    String price = dataFormatter.formatCellValue(row.getCell(3));//耗材单价
                    if (!price.equals("价格（元）")) {
                        return CommonResult.fail("导入数据第四列为价格");
                    }

                } else {
                    RepairConsume data = new RepairConsume();
                    //耗材名称
                    String name = dataFormatter.formatCellValue(row.getCell(0));
                    ConsumeNames.add(name);
                    if (ConsumeNames.stream().distinct().count() != ConsumeNames.size()) {
                        return CommonResult.fail("导入的Excel中" + name + "存在重复数据");
                    }
                    data.setName(name);
                    //校区
                    String schoolName = dataFormatter.formatCellValue(row.getCell(1));
                    Optional<RepairSchoolVo> school = schools.stream().filter(e -> e.getName().equals(schoolName)).findFirst();
                    if (school != null && school.isPresent()) {
                        data.setSchoolId(school.get().getId());
                    } else {
                        return CommonResult.fail(name + "的" + schoolName + "校区数据在数据库中不存在");
                    }

                    //重复数据提示
                    long exist = consumes.stream().filter(e -> e.getSchoolId().equals(school.get().getId()) && e.getName().equals(name)).count();
                    if (exist > 0) {
                        return CommonResult.fail(schoolName + "的" + name + "耗材数据在系统中已存在，请勿重复导入");
                    }

                    //报修物品（类别）
                    String article = dataFormatter.formatCellValue(row.getCell(2));
                    String[] articleStrs = null;
                    if (article.contains("、")) {
                        articleStrs = article.split("、");
                    } else if (article.contains(",")) {
                        articleStrs = article.split(",");
                    } else {
                        articleStrs = new String[1];
                        articleStrs[0] = article;
                    }
                    List<String> ass = new ArrayList<>();
                    for (String as : articleStrs) {
                        if (!as.equals("")) {
                            Optional<RepairArticleType> shiftData = articles.stream().filter(e -> e.getName().equals(as) && data.getSchoolId().equals(e.getSchoolId())).findFirst();
                            if (shiftData != null && shiftData.isPresent()) {
                                ass.add(shiftData.get().getId().toString());
                            } else {
                                return CommonResult.fail(name + "的" + as + "数据不存在");
                            }
                        }
                        data.setArticleId(StringUtils.join(ass, ','));
                        result.add(data);
                    }

                    //价格
                    BigDecimal price = new BigDecimal(dataFormatter.formatCellValue(row.getCell(3)));
                    data.setPrice(price);
                }
            }
        } catch (Exception e) {
            return CommonResult.fail("请按模板格式导入数据");
        }

        return CommonResult.ok(result);
    }

    /**
     * 根据校区ID和关键字查询耗材二级数据
     * @param schoolId 校区ID
     * @return
     */
    @Override
    public CommonResult queryRepairConsumesBykey(int schoolId, String keyWord) {
        List<RepairArticleType> result = repairArticleTypeService.getRepairArticlesBySchoolId(schoolId);

        List<RepairConsume> consumeLists = repairConsumeService.getConsumesByKeyword(schoolId, keyWord);

        List<RepairConsumeTreeVo> datas = new ArrayList<>();
        for (RepairConsume data:consumeLists) {
            RepairConsumeTreeVo treeData = new RepairConsumeTreeVo();
            treeData.setName(data.getName());
            treeData.setId(data.getId());
            treeData.setParentId(Integer.valueOf(data.getArticleId()));
            treeData.setPrice(data.getPrice());
            treeData.setNumber(1);
            treeData.setSchoolId(data.getSchoolId());
            Optional<RepairArticleType> article = result.stream().filter(e -> e.getId().toString().equals(data.getArticleId())).findFirst();
            if(article != null && article.isPresent()){
                treeData.setParentName(article.get().getName());
            }
            datas.add(treeData);
        }

        return CommonResult.ok(datas);
    }


    /**
     * 根据校区ID查询耗材树形图结构数据
     * @param schoolId 校区ID
     * @return
     */
    @Override
    public CommonResult queryRepairConsumeTypeTree(int schoolId) {
        List<RepairArticleType> result = repairArticleTypeService.getRepairArticlesBySchoolId(schoolId);

        List<RepairConsume> consumeLists = repairConsumeService.getConsumesByKeyword(schoolId, null);

        List<RepairConsumeypeTreeVo> datas = new ArrayList<>();
        for (RepairArticleType data:result) {
            RepairConsumeypeTreeVo newData = new RepairConsumeypeTreeVo().builder()
                    .id(data.getId())
                    .schoolId(data.getSchoolId())
                    .parentId(0)
                    .price(null)
                    .name(data.getName())
                    .build();
            List<RepairConsumeypeTreeVo> consumes = QueryArticleTypeTreeRecords(newData.getId(), newData.getName(), consumeLists);
            newData.setChildren(consumes);
            datas.add(newData);
        }

        return CommonResult.ok(datas);
    }

    /**
     * 根据父级ID获取树形菜单数据
     * @param parentID 父级ID
     * @param lists 数据集合
     * @return
     */
    private List<RepairConsumeypeTreeVo> QueryArticleTypeTreeRecords(Integer parentID, String parentName, List<RepairConsume> lists) {
        List<RepairConsumeypeTreeVo> newTrees = new ArrayList<>();

        List<RepairConsume> datas = lists.stream().filter(e -> e.getArticleId().equals(parentID.toString())).collect(Collectors.toList());

        for (RepairConsume data : datas) {
            RepairConsumeypeTreeVo item = RepairConsumeypeTreeVo.builder()
                    .id(data.getId())
                    .schoolId(data.getSchoolId())
                    .parentId(Integer.valueOf(data.getArticleId()))
                    .parentName(parentName)
                    .price(data.getPrice())
                    .name(data.getName())
                    .number(1)
                    .build();
            List<RepairConsumeypeTreeVo> news = QueryArticleTypeTreeRecords(item.getId(), item.getName(), lists);
            if (news == null || news.size() == 0) {
                newTrees.add(item);
                continue;
            } else {
                item.setChildren(news);
                newTrees.add(item);
            }
        }

        return newTrees;
    }
}

