package com.testor.module.video.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.biz.file.model.domain.SysFile;
import com.testor.biz.file.service.SysFileService;
import com.testor.biz.sys.org.model.domain.SysOrg;
import com.testor.biz.sys.org.service.SysOrgService;
import com.testor.ddd.safetyControl.application.service.spaceManage.SpaceManageService;
import com.testor.ddd.safetyControl.infrastructure.repository.space.dao.TSafeSpaceDao;
import com.testor.ddd.safetyControl.infrastructure.uitls.SpaceLevelEnum;
import com.testor.ddd.safetyControl.interfaces.model.dto.space.TSafeSpaceDTO;
import com.testor.ddd.safetyControl.interfaces.model.dto.space.TSafeSpaceDTOParam;
import com.testor.ddd.safetyControl.interfaces.model.vo.space.TSafeSpaceVO;
import com.testor.module.duty.model.dto.Person;
import com.testor.module.duty.util.PoiExcelUtils;
import com.testor.module.report.dto.ExplainDto;
import com.testor.module.report.dto.SysOrgDto;
import com.testor.module.report.dto.SysVideoInfoDto;
import com.testor.module.video.model.domain.SpaceTemplate;
import com.testor.module.video.model.dto.TVideoEquipmentInfoParam;
import com.testor.module.video.util.Beans;
import com.testor.module.video.util.ListUtils;
import com.testor.module.video.dao.TVideoEquipmentInfoDao;
import com.testor.module.video.model.domain.TVideoEquipmentInfo;
import com.testor.module.video.service.TVideoEquipmentInfoService;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.biz.models.BaseResponse;
import com.tongtech.tfw.backend.common.context.ContextUtils;
import com.tongtech.tfw.backend.common.exception.BusinessException;
import com.tongtech.tfw.backend.common.models.exceptions.ApiException;
import com.tongtech.tfw.backend.common.models.sys.UserInfo;
import com.tongtech.tfw.backend.core.helper.bean.BeanHelper;
import com.tongtech.tfw.workflow.apis.task.TaskEnumCode;
import com.tongtech.tfw.workflow.apis.task.model.dto.CompleteTask;
import com.tongtech.tfw.workflow.service.TfwTaskService;
import com.tongtech.tfw.workflow.service.dto.TaskCompleteParams;
import com.tongtech.tfw.workflow.service.dto.TaskServiceResult;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.tongtech.tfw.backend.common.models.supers.SuperServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 视频监控——设备信息Service业务层处理
 *
 * @author testor-framework
 * @date 2022-11-18 11:41:23
 */
@Service
public class TVideoEquipmentInfoServiceImpl extends SuperServiceImpl<TVideoEquipmentInfoDao, TVideoEquipmentInfo> implements TVideoEquipmentInfoService {
    @Autowired(required = false)
    private TVideoEquipmentInfoDao tVideoEquipmentInfoDao;
    @Autowired
    private SysOrgService sysOrgService;

    @Autowired
    private SpaceManageService spaceManageService;

    @Resource
    private SysFileService sysFileService;

    @Resource
    private TSafeSpaceDao spaceRepo;

    @Autowired
    private MinioClient minioClient;
    @Value("${minio.bucket}")
    private String bucketName;

    @Autowired
    private TfwTaskService tfwTaskService;

    @Override
    public BaseResponse imports(MultipartFile file) throws BusinessException {
        UserInfo loginUser = ContextUtils.getLoginUser();
        SysOrg sysOrg = sysOrgService.getById(loginUser.getOrgId());
        if (Objects.isNull(sysOrg)) {
            throw new BusinessException("当前登录人公司信息不存在，请联系管理员！");
        }
        Workbook workbook = null;
        InputStream inputStream = null;
        BaseResponse<List<Person>> response = new BaseResponse<>();
        List<Person> people = new ArrayList<>();
        try {
            inputStream = file.getInputStream();
            // 读取Excel⽂件⼯作表
            workbook = PoiExcelUtils.readFile(inputStream, file.getOriginalFilename());
            //取得第⼀个⼯作表
            Sheet sheet = workbook.getSheetAt(0);
            //报表上传的每条数据
            List<Map<Integer, Object>> list = PoiExcelUtils.getBody(sheet, 5, 1);
            //检查数据安全
            List<TVideoEquipmentInfo> videoList = checkReportData(list);
            //将设备编号相同，空间位置不同的数据合并成一条数据
            List<TVideoEquipmentInfo> dataList = mergent(videoList);
            //批量插入数据库
            for (TVideoEquipmentInfo tVideoEquipmentInfo : videoList) {
                int insert = tVideoEquipmentInfoDao.insert(tVideoEquipmentInfo);
            }
        } catch (IOException e) {
            throw new BusinessException("导入失败");
        } finally {
            try {
                if (null != workbook) {
                    workbook.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        BaseResponse baseResponse = new BaseResponse();
        baseResponse.setMsg("导入成功");
        return baseResponse;

    }

    private List<TVideoEquipmentInfo> mergent(List<TVideoEquipmentInfo> videoList) {
        Set<String> set = new HashSet<>();
        List<TVideoEquipmentInfo> res = new ArrayList<>();
        //重复的列表
        List<TVideoEquipmentInfo> repetList= new ArrayList<>();
        List<String> monitorList = new ArrayList<>();
        List<String> spaceList = new ArrayList<>();
        List<String> spaceTypeList = new ArrayList<>();
        for (TVideoEquipmentInfo tVideoEquipmentInfo : videoList) {
           set.add(tVideoEquipmentInfo.getDeviceId());
        }
        //取到所有的不重复的设备id
        for (String s : set) {
            TVideoEquipmentInfo videoEquipmentInfo = new TVideoEquipmentInfo();
            for (TVideoEquipmentInfo tVideoEquipmentInfo : videoList) {
                if (s.equals(tVideoEquipmentInfo.getDeviceId())){
                    monitorList.add(tVideoEquipmentInfo.getMonitorLocation());
                    spaceList.add(tVideoEquipmentInfo.getSpaceId());
                    spaceTypeList.add(tVideoEquipmentInfo.getSpaceTypeId());
                    BeanUtil.copyProperties(tVideoEquipmentInfo,videoEquipmentInfo);
                }
            }
            List list1 = ListUtils.removeDuplicationByHashSet(monitorList);
            List list2 = ListUtils.removeDuplicationByHashSet(spaceList);
            List list3 = ListUtils.removeDuplicationByHashSet(spaceTypeList);
            String monitorLocation = ListUtils.parseListToStr(list1);
            String spaceStr = ListUtils.parseListToStr(list2);
            String spaceTypeStr = ListUtils.parseListToStr(list3);
            videoEquipmentInfo.setMonitorLocation(monitorLocation);
            videoEquipmentInfo.setSpaceId(spaceStr);
            videoEquipmentInfo.setSpaceTypeId(spaceTypeStr);
            res.add(videoEquipmentInfo);
        }
        return res;
    }

    @Override
    public void downloadWorkareaTemplate(HttpServletResponse response, String fileDowName, String orgId) {
        try {
            List<SysFile> fileList = sysFileService.findByFileName(fileDowName);
            if (fileList == null || fileList.size() == 0) {
                return;
            }
            String fileDownName = fileList.get(0).getFileDowName();

            InputStream in = this.minioClient.getObject((GetObjectArgs) ((GetObjectArgs.Builder) ((GetObjectArgs.Builder) GetObjectArgs.builder().bucket(this.bucketName)).object(fileDownName)).build());

            String fileName2 = URLEncoder.encode(fileDowName, "UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName2);

            OutputStream outputStream = response.getOutputStream();

            List<SpaceTemplate> spaceList = findWorkshopList(orgId);

            ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(in).build();
            WriteSheet writeSheet2 = EasyExcel.writerSheet(3).head(SpaceTemplate.class).needHead(false).build();
            excelWriter.write(spaceList, writeSheet2);
            excelWriter.finish();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public IPage<TVideoEquipmentInfo> myList(Page<TVideoEquipmentInfo> resultPage, TVideoEquipmentInfoParam param) {
        IPage<TVideoEquipmentInfo> result = tVideoEquipmentInfoDao.myList(resultPage,param);
        return result;
    }

    @Override
    public void getTemplate(HttpServletRequest request, HttpServletResponse response, String orgId) {
        //ToDo 参考说明信息
        ExplainDto explainDto = new ExplainDto();
        explainDto.setExplain("\"说明：\n" +
                "      1.【企业名称】填写企业名称，依据“参考文件-企业信息”填写本单位相关内容\n" +
                "      2.【企业编号】填写企业编号，依据“参考文件-企业信息”填写相关内容\n" +
                "      3.【监控设备名称】填写监控设备名称，可自由填写，名称不可重复\n" +
                "      4.【监控设备编号】填写监控设备编号，根据编号规则填写，编号不可重复\n" +
                "      5.【安装位置】填写监控设备安装位置，可自由填写\n" +
                "      6.【监控作业区域名称】填写监控作业区域，一个摄像头可关联多个不同场所的不同作业区域，\n" +
                "                                             需分行单独填写（不要合并单元格）。依据”参考文件-作业区域统计”填写相关内容\n" +
                "      7.【作业区域编号】填写作业区域的编号，依据“参考文件-作业区域统计“填写相关内容\n" +
                "注意：\n" +
                "     1.带*号为必填项\n" +
                "     2.橙色区域为示例，不要进行修改\"");

        //todo  根据当前登录用户获取机构信息
        SysOrg one = (SysOrg)this.sysOrgService.getOne((Wrapper)((QueryWrapper)(new QueryWrapper())
                .eq("org_id", orgId)).ne("status", "1"));
        SysOrgDto sysOrgDto = Beans.objectToBean(one, SysOrgDto.class);

        //todo 获取当前机构作业区域列表
        TSafeSpaceDTOParam spaceDTOParam =new TSafeSpaceDTOParam();
        spaceDTOParam.setOrgId(orgId);
        spaceDTOParam.setLevel(2);
        List<TSafeSpaceVO> tSafeSpaceVOS = spaceRepo.listPageByWorkArea(spaceDTOParam);

        //todo 设备示例信息
        SysVideoInfoDto sysVideoInfoDto=new SysVideoInfoDto();
        sysVideoInfoDto.setOrgName("北京基层粮库");
        sysVideoInfoDto.setOrgCode("beijingliangku");
        sysVideoInfoDto.setEquipmentName("1号摄像头");
        sysVideoInfoDto.setDeviceId("beijing-jk-01");
        sysVideoInfoDto.setInstallationLocation("1号浅圆仓");
        sysVideoInfoDto.setLocationName("1号浅圆仓1号区域");
        sysVideoInfoDto.setLocationCode("beijing-qyc-01-01");

        Workbook workBook = new XSSFWorkbook();
        try {

            // 创建参数对象（用来设定excel的sheet1内容等信息）
            ExportParams userExportParams = new ExportParams();
            // 设置sheet得名称
            userExportParams.setSheetName("视频监控设备信息");
            // 创建sheet1使用得map
            Map<String, Object> userExportMap = new HashMap<>();
            // title的参数为ExportParams类型，目前仅仅在ExportParams中设置了sheetName
            userExportMap.put("title", userExportParams);
            // 模版导出对应得实体类型
            userExportMap.put("entity", SysVideoInfoDto.class);
            //转成导出vo类型
            List<SysVideoInfoDto> statisticsVOS = new ArrayList<>();
            List<ExplainDto> explainDtos = new ArrayList<>();
            List<SysOrgDto> sysOrgDtos = new ArrayList<>();
            sysOrgDtos.add(sysOrgDto);
            explainDtos.add(explainDto);
            statisticsVOS.add(sysVideoInfoDto);
            // sheet1中要填充得数据
            userExportMap.put("data", statisticsVOS);

            // 创建参数对象（用来设定excel的sheet2内容等信息）
            ExportParams logInfoExportParams = new ExportParams();
            logInfoExportParams.setSheetName("参考说明");
            // 创建sheet2使用的map
            Map<String, Object> logInfoExportMap = new HashMap<>();
            logInfoExportMap.put("title", logInfoExportParams);
            logInfoExportMap.put("entity", ExplainDto.class);
            // sheet2中要填充得数据
            logInfoExportMap.put("data", explainDtos);

            // 创建参数对象（用来设定excel的sheet3内容等信息）
            ExportParams sysOrg = new ExportParams();
            sysOrg.setSheetName("参照文件-企业信息");
            // 创建sheet2使用的map
            Map<String, Object> sysOrgExportMap = new HashMap<>();
            sysOrgExportMap.put("title", sysOrg);
            sysOrgExportMap.put("entity", SysOrgDto.class);
            // sheet2中要填充得数据
            sysOrgExportMap.put("data", sysOrgDtos);


            // 创建参数对象（用来设定excel的sheet4内容等信息）
            ExportParams tSafeSpaceExportParams = new ExportParams();
            tSafeSpaceExportParams.setSheetName("参照文件-作业区域统计");
            // 创建sheet2使用的map
            Map<String, Object> tSafeSpaceExportMap = new HashMap<>();
            tSafeSpaceExportMap.put("title", tSafeSpaceExportParams);
            tSafeSpaceExportMap.put("entity", TSafeSpaceVO.class);
            // sheet2中要填充得数据
            tSafeSpaceExportMap.put("data", tSafeSpaceVOS);


            // 将sheet1、sheet2使用得map进行包装
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            //后续增加sheet组，则后面继续追加即可;
            sheetsList.add(userExportMap);
            sheetsList.add(logInfoExportMap);
            sheetsList.add(sysOrgExportMap);
            sheetsList.add(tSafeSpaceExportMap);

            // 执行方法
            workBook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
            //设置编码格式
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            //设置内容类型
            response.setContentType("application/octet-stream");
            //设置头及文件命名。
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("视频监控设备量导入模板.xls", StandardCharsets.UTF_8.name()));
            //ToDo 设置单元格颜色
            Sheet sheet = workBook.getSheetAt(0);
            Row row = sheet.getRow(1);
            short lastCellNum = row.getLastCellNum();
            for (int i = 0; i <lastCellNum; i++) {
                Cell cellColor = row.getCell(i);
                CellStyle style = workBook.createCellStyle();
                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                style.setFillForegroundColor((short) 53);
                cellColor.setCellStyle(style);
            }


            //写出流
            workBook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (workBook != null) {
                try {
                    //强行关流
                    workBook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }}

    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void completeTask(CompleteTask completeTask) {

        try {
            TaskCompleteParams taskCompleteParams = (TaskCompleteParams) BeanHelper.beanToBean(completeTask, TaskCompleteParams.class);
            TaskServiceResult taskServiceResult = tfwTaskService.completeTask(taskCompleteParams);
        } catch (Exception var5) {
//            log.error("完成任务 ERROR: " + var5);
            var5.printStackTrace();
            throw new ApiException(TaskEnumCode.COMPLETE_FAILED.transform());
        }
    }


    private List<TVideoEquipmentInfo> checkReportData(List<Map<Integer, Object>> list) throws BusinessException {
        List<TVideoEquipmentInfo> listmonth = new ArrayList<>();
        for (Map<Integer, Object> item : list) {
            //监控设备名称
            String equipmentName = item.get(0).toString();
            //监控设备编号
            String deviceId = item.get(1).toString();
            //安装位置
            String installationLocation = item.get(2).toString();
            //监控作业区域名称
            String monitorLocation = item.get(3).toString();
            //监控作业区域编号
            String monitorLocationId = item.get(4).toString();
            //根据监控位置获取设备信息
            //将默认数据写入对象中
            TVideoEquipmentInfo videoEquipmentInfo = new TVideoEquipmentInfo();
            String orgId = ContextUtils.getLoginUser().getOrgId();
            SysOrg byId = sysOrgService.getById(orgId);
            String orgName = byId.getOrgName();
            BigDecimal treeLevel = byId.getTreeLevel();
            int i = treeLevel.compareTo(new BigDecimal("3"));
            if (i < 0) {
                throw new BusinessException("只有粮库才能上传视频设备信息");
            } else if (i > 0) {
                String[] split = byId.getParentIds().split(",");
                String parentId = split[2];
                SysOrg byId1 = sysOrgService.getById(parentId);
                orgId = parentId;
                orgName = byId1.getOrgName();
            }
            videoEquipmentInfo.setOrgId(orgId);
            videoEquipmentInfo.setOrgName(orgName);
            //检查是否有必填的没有填
            if (StringUtils.isBlank(equipmentName) || StringUtils.isBlank(installationLocation) || StringUtils.isBlank(deviceId) || StringUtils.isBlank(monitorLocation)) {
                throw new BusinessException("有必填参数没有填写");
            }
            //校验监控设备名称，监控设备编号不能重复
            QueryWrapper<TVideoEquipmentInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("status","0").and(wrapper->wrapper.eq("equipment_name",equipmentName).or().eq("device_id",deviceId));
            int count = tVideoEquipmentInfoDao.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException("监控设备和监控设备编号不能重复");
            }
            //组装数据，将监控设备编号相同的监控作业区域信息放在一起
            this.getSpaceInfo(videoEquipmentInfo, monitorLocationId,orgId);
            listmonth.add(videoEquipmentInfo);
        }
        if (listmonth.size() == 0) {
            throw new BusinessException("请勿上传空模板");
        }
        return listmonth;
    }

    private void getSpaceInfo(TVideoEquipmentInfo videoEquipmentInfo, String monitorLocationId,String orgId) throws BusinessException {
        //根据地点id获取空间信息
        //根据id获取空间信息
        TSafeSpaceDTO safeSpaceDTO = spaceManageService.findBySpaceName(monitorLocationId, orgId);
        if (safeSpaceDTO == null) {
            throw new BusinessException("空间位置不存在");
        }
        videoEquipmentInfo.setSpaceId(safeSpaceDTO.getSpaceId());
        videoEquipmentInfo.setSpaceTypeId(safeSpaceDTO.getSpaceTypeId());
        videoEquipmentInfo.setMonitorLocation(safeSpaceDTO.getId());

    }

    /**
     * 获取 车间场所信息
     *
     * @param orgId
     * @return
     */
    public List<SpaceTemplate> findWorkshopList(String orgId) {
        if (StrUtil.isBlank(orgId)) {
            return null;
        }
        TSafeSpaceDTOParam spaceDTOParam = new TSafeSpaceDTOParam();
        spaceDTOParam.setStatus(BizConstants.STATUS_ENABLE);
        spaceDTOParam.setOrgId(orgId);
        spaceDTOParam.setLevel(SpaceLevelEnum.workshop.getCode());
        List<TSafeSpaceVO> spaceDTOList = spaceManageService.listByPage(spaceDTOParam).getData();

        if (spaceDTOList == null || spaceDTOList.size() == 0) {
            return null;
        }

        List<SpaceTemplate> templateEntityList = spaceDTOList.stream().map(p -> new SpaceTemplate(p.getSpaceName(), p.getSpaceCode())).collect(Collectors.toList());
        return templateEntityList;
    }
}
