package cn.com.ty.lift.business.maintenance.service;

import cn.com.ty.lift.business.common.http.BasicHttpClient;
import cn.com.ty.lift.business.common.http.HttpClient;
import cn.com.ty.lift.business.evaluation.dao.entity.Evaluation;
import cn.com.ty.lift.business.evaluation.service.EvaluationService;
import cn.com.ty.lift.business.framework.util.MessageUtils;
import cn.com.ty.lift.business.library.dao.entity.Lift;
import cn.com.ty.lift.business.library.service.LiftService;
import cn.com.ty.lift.business.maintenance.dao.entity.*;
import cn.com.ty.lift.business.maintenance.dao.entity.model.request.MaintenanceRecordRequest;
import cn.com.ty.lift.business.maintenance.dao.entity.model.request.MtRecordRequest;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MaintenanceRecordDetailResponse;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MaintenanceRecordResponse;
import cn.com.ty.lift.business.maintenance.dao.entity.model.response.MtRecordResponse;
import cn.com.ty.lift.business.maintenance.dao.mapper.MaintenanceOptionMapper;
import cn.com.ty.lift.business.maintenance.dao.mapper.MaintenancePlanMapper;
import cn.com.ty.lift.business.maintenance.dao.mapper.MaintenanceRecordMapper;
import cn.com.ty.lift.business.maintenance.dao.third.*;
import cn.com.ty.lift.business.project.dao.entity.Project;
import cn.com.ty.lift.business.project.dao.entity.ProjectLiftRelevance;
import cn.com.ty.lift.business.project.service.ProjectLiftRelevanceService;
import cn.com.ty.lift.business.project.service.ProjectService;
import cn.com.ty.lift.common.constants.CommonEnum;
import cn.com.ty.lift.common.utils.DateUtils;
import cn.com.ty.lift.common.utils.MapHelper;
import cn.com.ty.lift.common.utils.ValuePool;
import cn.com.ty.lift.common.verify.Val;
import cn.com.ty.lift.common.verify.Validate;
import cn.com.xwy.boot.web.dto.RestResponse;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Splitter;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bieao
 * @date 2019/12/12
 * @description 保养记录业务层
 */
@Service
@Slf4j
@AllArgsConstructor
public class MaintenanceRecordService extends ServiceImpl<MaintenanceRecordMapper, MaintenanceRecord> {


    private LiftService liftService;
    private MtRecordCostService mtRecordCostService;
    private MtRecordImgService mtRecordImgService;
    private MaintenancePlanService maintenancePlanService;
    private EvaluationService evaluationService;
    private ProjectService projectService;
    private ProjectLiftRelevanceService projectLiftRelevanceService;
    private MaintenanceOptionMapper maintenanceOptionMapper;
    private MaintenancePlanMapper maintenancePlanMapper;
    private Gson gson;
    MaintenanceOptionService maintenanceOptionService;

    @Autowired
    private Environment env;

    /**
     * @param request 公司id和电梯id
     * @return RestResponse 保养信息
     * @description 根据公司id和电梯id查询上次保养信息
     * @date 2020/1/6 5:37 下午
     */
    public MaintenanceRecordResponse recordInfo(MaintenanceRecordRequest request) {
        MaintenanceRecordResponse project = baseMapper.findProjectByCompanyId(request);
        MaintenanceRecordResponse record = baseMapper.findRecordByCompanyId(request);
        if (ObjectUtil.isNotEmpty(record)) {
            project.setType(record.getType());
            project.setWorkDate(record.getWorkDate());
            //获取保养期数
            Long mtPlanId = record.getMtPlanId();
            Long count = maintenancePlanMapper.getCountByPlanId(mtPlanId);
            project.setPeriods(count);
            project.setMtPlanId(mtPlanId);
            return project;
        }
        return project;
    }

    /**
     * @param id 电梯id
     * @return 电梯经纬度
     * @description 根据电梯id获取经纬度
     * @date 2020/1/13 11:37 上午
     */
    public String getCoordinate(Long id) {
        Lift lift = liftService.getById(id);
        return Optional.ofNullable(lift).map(Lift::getCoordinate).orElse(null);
    }


    /**
     * @param coordinate 维保工经纬度
     * @return 是否在范围内
     * @description 计算维保工开始保养时，是否在电梯200米范围内
     * @date 2020/1/13 11:30 上午
     */
    public boolean calc(String liftCoordinate, String coordinate) {
        double expected = 500;
        double result = MapHelper.GetPointDistance(liftCoordinate, coordinate);
        return (result * 1000) > expected;
    }

    /**
     * @param planId      计划id
     * @param mtCompanyId 公司id
     * @return 是否存在
     * @description 根据计划id和公司id查询是否有保养记录
     * @date 2020/1/20 2:41 下午
     */
    public MaintenanceRecord findOne(Long planId, Long mtCompanyId, Long liftId) {
        LambdaQueryWrapper<MaintenanceRecord> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(MaintenanceRecord::getMtPlanId, planId);
        lambdaQueryWrapper.eq(MaintenanceRecord::getMtCompanyId, mtCompanyId);
        lambdaQueryWrapper.eq(MaintenanceRecord::getLiftId, liftId);
        return getOne(lambdaQueryWrapper);
    }

    /**
     * @param request 修改维保计划请求
     * @return 是否修改成功
     * @description 修改维保计划
     * @date 2020/5/12 2:03 下午
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean modifyPlan(MaintenanceRecordRequest request) {
        MaintenanceRecord record = request.getRecord();
        //获取公司id
        Long mtCompanyId = record.getMtCompanyId();
        //获取电梯id
        Long liftId = record.getLiftId();
        //获取项目id
        Long projectId = record.getProjectId();
        //获取维保工id
        Long workerId = record.getWorkerId();
        MaintenancePlan plan = new MaintenancePlan();
        plan.setProjectId(projectId);
        plan.setMtCompanyId(mtCompanyId);
        plan.setLiftId(liftId);
        plan.setWorkerId(workerId);
        Optional<Project> optional = projectService.getOne(projectId);
        Project project = new Project();
        if (optional.isPresent()) project = optional.get();
        if (ObjectUtil.isEmpty(project)) return false;
        //项目结束时间默认增加三个月
        LocalDate endDate = project.getEndDate().plusMonths(3);
        //获取当前期数
        Integer periods = request.getPeriods();
        //获取当前电梯的保养间隔
        ProjectLiftRelevance entry = projectLiftRelevanceService.getOne(mtCompanyId, liftId);
        if (ObjectUtil.isEmpty(entry)) return false;
        int interval = entry.getPlanInterval();
        List<MaintenancePlan> planList = maintenancePlanService.findPlanList(liftId, projectId, mtCompanyId, request.getCurrentTime(), "record");
        //提前保养跳过当前保养的计划
        Iterator<MaintenancePlan> iterator = planList.iterator();
        if (iterator.hasNext()) {
            MaintenancePlan next = iterator.next();
            if (Objects.nonNull(next))
                iterator.remove();
        }
        //获取当前时间后的维保计划列表，并清除计划
        maintenancePlanService.removeByIds(planList.stream().map(MaintenancePlan::getId).collect(Collectors.toList()));
        //按照修改时间重新生成计划
        LocalDate beginTime = request.getCurrentTime().plusDays(interval);
        List<MaintenancePlan> plans = maintenancePlanService.generatePlan(plan, periods, interval, beginTime, endDate);
        return maintenancePlanService.saveBatch(plans, plans.size());
    }

    /**
     * @param request 保养单信息
     * @return 是否成功
     * @description 新增保养记录
     * @date 2020/1/13 1:47 下午
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse saveRecord(MaintenanceRecordRequest request) {
        MaintenanceRecord record = request.getRecord();
        Long planId = record.getMtPlanId();
        Long mtCompanyId = record.getMtCompanyId();
        Long liftId = record.getLiftId();
        request.setCurrentTime(LocalDate.now());
        //校验电梯是否定位
        String liftCoordinate = getCoordinate(liftId);
        if (StrUtil.isEmpty(liftCoordinate)) return RestResponse.fail(MessageUtils.get("msg.lift.not.position"));
        //校验是否为经纬度
//        boolean verifyResult = VerifyUtils.preJudgment(coordinate);
//        if (!verifyResult)
//            return RestResponse.fail(MessageUtils.get("msg.longitude.error"));
        //维保工是否在电梯附近
        String coordinate = request.getCoordinate();
        boolean result = calc(liftCoordinate, coordinate);
        if (result)
            return RestResponse.fail(MessageUtils.get("msg.error.person.scope"));
        MaintenancePlan plan = maintenancePlanService.getOne(record.getMtPlanId());
        if (ObjectUtil.isEmpty(plan)) return RestResponse.fail(MessageUtils.get("msg.maintenance.plan.not.exist"));

        //根据期数计算维保类型
        Integer periods = request.getPeriods();
        //保养类型 1.半月，2.季度，3.半年，4.全年
        int[] maintenanceType = {1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 4};
        int length = maintenanceType.length;
        int type;
        int mod = periods % length;
        //设置维保类型
        if (mod == 0) {
            type = maintenanceType[length - 1];
        } else {
            type = maintenanceType[mod - 1];
        }
        plan.setStatus(Integer.parseInt(CommonEnum.MaintenancePlanStatus.MAINTENANCE_DOING.getCode()));
        plan.setType(type);
        plan.setCount(request.getPeriods());
        boolean planResult = maintenancePlanService.updateById(plan);
        if (!planResult) {
            rollback();
            return RestResponse.fail(MessageUtils.get("msg.add.fail"));
        }
        //若保养时间在计划时间之前，则需要修改维保计划
        boolean compareResult = request.getCurrentTime().isBefore(plan.getPlanDate());
        if (compareResult) {
            boolean modifyPlan = modifyPlan(request);
            if (!modifyPlan) {
                return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
            }
        }
        Optional<Lift> lift = liftService.getOne(null, liftId);
        if (lift.isPresent()) {
            Lift l = lift.get();
            record.setCode(l.getLiftCode());
            record.setLiftType(l.getLiftType());
            record.setType(type);
            record.setStatus(CommonEnum.MaintenanceRecordStatus.MAINTENANCE_DOING.getCode());
            record.setWorkerId1(record.getWorkerId1());
            record.setWorkDate(LocalDateTime.now());
            record.setPlanDate(plan.getPlanDate());
            record.setStopDate(LocalDateTime.now());
            MaintenanceRecord one = findOne(planId, mtCompanyId, liftId);
            if (Objects.isNull(one)) {
                boolean ret = save(record);
                if (!ret) {
                    rollback();
                    return RestResponse.fail(MessageUtils.get("msg.add.fail"));
                }
            } else {
                record.setId(one.getId());
                boolean ret = updateById(record);
                if (!ret) {
                    rollback();
                    return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
                }
            }
        } else {
            return RestResponse.fail(MessageUtils.get("msg.add.fail"));
        }
        return RestResponse.success(record.getId(), MessageUtils.get("msg.add.success"));
    }

    /**
     * @param params 获取任务单入参
     * @return GetMission 任务单信息
     * @description 获取任务单
     * @date 2020/5/18 2:51 下午
     */
    public GetMission getMission(Map<String, Object> params) {
        log.info("调用第三方接口获取任务单");
        String url = env.getProperty("get.mission");
        ThirdPartyInterfaceResponse<GetMission> response = HttpClient.getInstance().send(url, params, BasicHttpClient.jsonHeaders)
                .convert(new TypeToken<ThirdPartyInterfaceResponse<GetMission>>() {
                }.getType());
        GetMission getMission = null;
        try {
            if (Objects.nonNull(response)) {
                if (Objects.equals(0, response.getCode())) {
                    getMission = response.getData();
                }
            }
        } catch (Exception e) {
            log.error("获取任务单数据失败", e);
        }
        log.info("结束调用第三方任务单接口");
        return getMission;
    }

    /**
     * @param params RwdId 开始维保入参
     * @return List<BeginMission> 需要维保的项
     * @description 开始维保
     * @date 2020/5/19 2:41 下午
     */
    public List<BeginMission> beginMaintenance(Map<String, Object> params, String rwdId) {
        Map<String, Object> map = new HashMap<>();
        map.put("RwdId", rwdId);
        params.put("Content", map);
        String url = env.getProperty("begin.maintenance");
        log.info("调用第三方接口开始维保任务");
        ThirdPartyInterfaceResponse<List<BeginMission>> response = HttpClient.getInstance().send(url, params, BasicHttpClient.jsonHeaders)
                .convert(new TypeToken<ThirdPartyInterfaceResponse<List<BeginMission>>>() {
                }.getType());
        List<BeginMission> missions = null;
        try {
            if (Objects.nonNull(response)) {
                if (Objects.equals(0, response.getCode())) {
                    missions = response.getData();
                }
            }
        } catch (Exception e) {
            log.error("开始维保任务失败", e);
        }
        log.info("结束调用第三方开始维保任务接口");
        return missions;
    }

    /**
     * @param params      RwdId,token,account 完成维保入参
     * @param mtCompanyId 公司ID
     * @description 完成维保
     * @date 2020/5/19 4:01 下午
     */
    public void endMaintenance(Map<String, Object> params, Long mtCompanyId, Long recordId, String rwdId, Long liftId) {
        //查询维保记录
        MaintenanceTask task = baseMapper.queryMaintenanceTask(mtCompanyId, liftId);
        params.remove("Content");
        params.put("RwdId", rwdId);
        //需物业配合事项
        params.put("Items", "");
        //维保报告
        params.put("Report", task.getMaintenanceAdvice());
        //作业类型
        params.put("OpeateType", task.getType());
        //实际维保人操作证ID
        params.put("CardId", task.getCode());
        //媒体类型
        params.put("MdeiaType", "照片");
        //获取维保图片地址
        List<String> urlList = baseMapper.getMaintenanceRecordUrl(task.getId());
        List<RecordContent> Records = new ArrayList<>();
        for (String s : urlList) {
            RecordContent recordContent = new RecordContent();
            recordContent.setMaterialUrl(s);
            Records.add(recordContent);
        }
        //封装维保项数据
        MaintenanceRecord record = getById(recordId);
        List<MaintenanceOption> optionList = maintenanceOptionMapper.getOptionList();
        List<Map<String, String>> returnList = new ArrayList<>();
        if (Objects.nonNull(record)) {
            String option = record.getMaintenanceOption();
            String[] split = option.split(",");
            for (String s : split) {
                for (MaintenanceOption entry : optionList) {
                    String[] split1 = s.split(":");
                    if (split1.length > 1) {
                        String id = split1[0];
                        String result = split1[1];
                        String optionId = Objects.toString(entry.getId());
                        if (id.equals(optionId)) {
                            Map<String, String> paramMap = new HashMap<>();
                            paramMap.put("CkItem", entry.getItem());
                            paramMap.put("CkContent", entry.getContent());
                            paramMap.put("Ckresult", result.equals("0") ? "无此项" : (result.equals("1") ? "正常" : "需修理"));
                            returnList.add(paramMap);
                        }
                    }
                }
            }
        }
        ItemContent content = new ItemContent();
        content.setWbItems(returnList);
        content.setRecords(Records);
        params.put("Content", content);

        String url = env.getProperty("end.maintenance");

        log.info("调用第三方接口完成维保任务");
        ThirdPartyInterfaceResponse response = HttpClient.getInstance().send(url, params, BasicHttpClient.jsonHeaders)
                .convert(new TypeToken<ThirdPartyInterfaceResponse>() {
                }.getType());
        try {
            if (Objects.nonNull(response)) {
                if (Objects.equals(0, response.getCode())) {
                    log.info("维保记录提交成功");
                }
            }
        } catch (Exception e) {
            log.error("完成维保任务失败", e);
        }
        log.info("结束调用第三方完成维保任务接口");
    }

    /**
     * @param params      RwdId,token,account 提交维保记录入参
     * @param mtCompanyId 公司ID
     * @description 提交维保记录
     * @date 2020/5/19 2:55 下午
     */
    public void commitMaintenanceRecord(Map<String, Object> params, Long mtCompanyId, Long recordId, Long liftId) {
        //获取任务单
        GetMission mission = getMission(params);
        if (Objects.isNull(mission)) {
            log.warn("获取任务单失败");
            //TODO 回补机制待完善
        } else {
            String rwdId = mission.getRwdId();
            //开始维保任务
            List<BeginMission> missions = beginMaintenance(params, rwdId);
            if (Objects.isNull(missions)) {
                log.warn("开始维保任务失败");
            } else {
                if (CollUtil.isNotEmpty(missions)) {
                    //结束维保任务，提交保养记录
                    endMaintenance(params, mtCompanyId, recordId, rwdId, liftId);
                }
            }
        }
    }

    /**
     * @param request 保养信息
     * @return 是否成功
     * @description 编辑保养信息
     * @date 2020/1/13 2:31 下午
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse modify(MaintenanceRecordRequest request) {
        MaintenanceRecord record = request.getRecord();
        MaintenanceRecord oldRecord = detail(record.getId());
        if (Objects.isNull(oldRecord))
            return RestResponse.success(null, MessageUtils.get("msg.record.not.exist"));

        record.setStatus(CommonEnum.MaintenanceRecordStatus.COMPLETE.getCode());
        record.setRecoveryDate(LocalDateTime.now());
        boolean result = updateById(record);
        if (!result) {
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        MaintenancePlan plan = maintenancePlanService.getOne(oldRecord.getMtPlanId());
        if (ObjectUtil.isEmpty(plan)) return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        plan.setStatus(Integer.parseInt(CommonEnum.MaintenancePlanStatus.COMPLETE.getCode()));
        plan.setWorkDate(LocalDateTime.now());
        //修改保养计划为完成
        boolean planResult = maintenancePlanService.updateById(plan);
        if (!planResult) {
            rollback();
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        List<MtRecordImg> imageList = new ArrayList<>();
        //更新保养图片
        request.getRecordImageList().forEach(entry -> {
            MtRecordImg image = new MtRecordImg();
            image.setImgUrl(entry);
            image.setMtRecordId(record.getId());
            imageList.add(image);
        });
        Long mtCompanyId = request.getMtCompanyId();
        //苏州帝威电梯工程技术有限公司 - 发送维保记录数据
        if (Objects.equals(1001102109977L, mtCompanyId)) {
            String registrationCode = StrUtil.EMPTY;
            Long liftId = oldRecord.getLiftId();
            Optional<Lift> optional = liftService.getOne(null, liftId);
            if (optional.isPresent()) {
                Lift lift = optional.get();
                registrationCode = lift.getRegistrationCode();
            }
            Long recordId = record.getId();
            //获取维保人员ID
            Long workerId1 = oldRecord.getWorkerId1();
            //查询维保人员操作证
            String cardId = baseMapper.getCardId(workerId1);
            MissionContent content = new MissionContent();
            content.setDevCode(registrationCode);
            content.setCardNoList(cardId);

            Map<String, Object> params = new HashMap<>();
            params.put("token", env.getProperty("token"));
            params.put("account", env.getProperty("account"));
            params.put("Content", content);
            //提交维保记录
            commitMaintenanceRecord(params, mtCompanyId, recordId, liftId);
        }
        boolean ret = mtRecordImgService.saveBatch(imageList, imageList.size());
        if (!ret) {
            rollback();
            return RestResponse.fail(MessageUtils.get("msg.modify.fail"));
        }
        return RestResponse.success(null, MessageUtils.get("msg.modify.success"));
    }

    /**
     * @param id 保养记录id
     * @return 保养信息详情
     * @description 查看保养信息详情
     * @date 2020/1/13 2:39 下午
     */
    public MaintenanceRecord detail(Long id) {
        return getById(id);
    }

    /**
     * @param id 保养记录id
     * @return 保养信息详情
     * @description 查看保养信息详情
     * @date 2020/1/13 2:39 下午
     */
    @Deprecated
    public MaintenanceRecordDetailResponse queryById(Long id) {
        MaintenanceRecord record = getById(id);
        List<MtRecordImg> imgList = mtRecordImgService.listByRecord(id);
        MaintenanceRecordDetailResponse response = new MaintenanceRecordDetailResponse();
        response.setRecord(record);
        response.setRecordImageList(imgList);
        return response;
    }

    /**
     * @param repairDiff 分钟数
     * @return 时分
     * @description 计算时长
     * @date 2020/5/23 11:58 上午
     */
    public String getRepairDuration(int repairDiff) {
        String time;
        if (repairDiff == 60) {
            int hours = repairDiff / 60;
            time = hours + "小时";
        } else if (repairDiff > 60) {
            int hours = repairDiff / 60;
            int minute = repairDiff % 60;
            time = hours + "小时" + minute + "分钟";
        } else {
            time = repairDiff + "分钟";
        }
        return time;
    }

    /**
     * 根据条件分页查询维保-日常保养
     *
     * @param request MtRecordRequest
     * @return IPage<MtRecordResponse>
     * @author wcz
     */
    public IPage<MtRecordResponse> pageRecordByCondition(MtRecordRequest request) {
        IPage<MtRecordResponse> page = baseMapper.pageRecordByCondition(request.getPage(), request);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            List<MtRecordResponse> records = page.getRecords();
            for (MtRecordResponse mtRecord : records) {
                String repairDuration = getRepairDuration(mtRecord.getRepairDiff());
                mtRecord.setRepairDuration(repairDuration);
            }
        }
        return page;
    }

    /**
     * 根据维保公司统计维保-日常保养
     *
     * @param request MtRecordRequest
     * @return long
     * @author wcz
     */
    public long countRecordByCondition(MtRecordRequest request) {
        return baseMapper.countRecordByCondition(request);
    }

    /**
     * 日常保养-保养单：根据id查询,带关联信息
     *
     * @param request MtRecordRequest
     * @return boolean
     * @author wcz
     */
    public MtRecordResponse infoById(MtRecordRequest request) {
        return baseMapper.infoById(request);
    }

    /**
     * 批量打印
     *
     * @param request
     * @return
     */
    public List<MtRecordResponse> listByIds(MtRecordRequest request) {
        return baseMapper.listByIds(request);
    }

    private void rollback() {
        //强制手动事务回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

    /**
     * 点击填写保养单，带收费项，新增record
     *
     * @param entity MaintenanceRecord
     * @return boolean
     * @author wcz
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse tofill(MaintenanceRecord entity) {
        //总计 partsCost, manCost, 拼接sparepart
        List<MtRecordCost> mtRecordCosts = entity.getMtRecordCosts();
        //修复空指针异常，赋值默认值
        ArrayList<MtRecordCost> removeList = new ArrayList<>();
        for (MtRecordCost mtRecordCost : mtRecordCosts) {
            if (mtRecordCost.getSparepart() == null || "".equals(mtRecordCost.getSparepart())) {
                removeList.add(mtRecordCost);
                continue;
            }
            if (mtRecordCost.getManCost() == null) {
                mtRecordCost.setManCost(new BigDecimal("0.00"));
            }
            if (mtRecordCost.getPartsCost() == null) {
                mtRecordCost.setPartsCost(new BigDecimal("0.00"));
            }
        }
        //将未设置零配件名字的从配件列表中移除
        mtRecordCosts.removeAll(removeList);

        if (IterUtil.isNotEmpty(mtRecordCosts)) {
            BigDecimal partsCost = mtRecordCosts.stream().map(MtRecordCost::getPartsCost).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal manCost = mtRecordCosts.stream().map(MtRecordCost::getManCost).reduce(BigDecimal.ZERO, BigDecimal::add);
            String sparepart = mtRecordCosts.stream().map(MtRecordCost::getSparepart).collect(Collectors.joining(";"));
            entity.setPartsCost(partsCost);
            entity.setManCost(manCost);
            entity.setSparepart(sparepart);
        }
        boolean mr = saveOrUpdate(entity);
        if (!mr) {
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        //如果没有收费项
        if (IterUtil.isEmpty(mtRecordCosts)) {
            return RestResponse.success(entity.getId());
        }
        mtRecordCosts.forEach(cost -> {
            cost.setMtRecordId(entity.getId());
        });
        boolean rc = mtRecordCostService.saveOrUpdateBatch(mtRecordCosts, mtRecordCosts.size());
        if (!rc) {
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养收费项失败，请稍后重试");
        }
        MaintenancePlan plan = maintenancePlanService.getById(entity.getMtPlanId());
        if (Objects.isNull(plan)) {
            return RestResponse.success(entity.getId());
        }
        plan.setWorkDate(LocalDateTime.now());
        boolean mp = maintenancePlanService.updateById(plan);
        if (mp) {
            return RestResponse.success(entity.getId());
        } else {
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养计划执行时间失败，请稍后重试");
        }
    }

    /**
     * 工单补录
     *
     * @param request 维保记录id 和相应数据
     * @return boolean
     * @author wcz
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse fill(MtRecordRequest request) {
        Long recordId = request.getId();
        //获取维保记录
        MaintenanceRecord record = this.getById(recordId);
        Validate.notNull(record, ValuePool.MAINTENANCE_RECORD_NOT_EXIST);
        //获取维保计划
        MaintenancePlan plan = maintenancePlanService.getOne(record.getMtPlanId());
        Validate.notNull(plan, ValuePool.MAINTENANCE_PLAN_NOT_EXIST);
        //更新状态 - 维保记录
        record.setMaintenanceOption(request.getMaintenanceOption());
        record.setStatus(CommonEnum.MaintenanceRecordStatus.COMPLETE.getCode());
        record.setWorkDate(LocalDateTime.now());
        boolean mr = saveOrUpdate(record);
        if (!mr) {
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        //更新状态 - 维保计划
        plan.setStatus(Integer.parseInt(CommonEnum.MaintenancePlanStatus.COMPLETE.getCode()));
        plan.setWorkDate(LocalDateTime.now());
        if (!maintenancePlanService.updateById(plan)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return RestResponse.fail("更新保养计划失败，请稍后重试");
        }
        //保存维保收费项
        List<String> imgs = request.getImgs();
        if (IterUtil.isEmpty(imgs)) {
            return RestResponse.success(true);
        }
        List<MtRecordImg> mtRecordImgs = new ArrayList<>();
        for (int i = 0; i < imgs.size(); i++) {
            MtRecordImg mri = new MtRecordImg();
            mri.setMtRecordId(record.getId());
            mri.setImgUrl(imgs.get(i));
            mri.setSort(i);
            mtRecordImgs.add(mri);
        }
        boolean mi = mtRecordImgService.saveBatch(mtRecordImgs, mtRecordImgs.size());
        if (mi) {
            return RestResponse.success(true);
        } else {
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改保养单收费项失败，请稍后重试");
        }
    }

    /**
     * 通过：app端提交的保养单点通过后生成正式保养单  status:-1 -> 2
     * 清除超期: 超期的计划修改status ->1,workDate -> now
     *
     * @param entity MaintenanceRecord
     * @return boolean
     * @author wcz
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse pass(MaintenanceRecord entity) {
        boolean mr = updateById(entity);
        if (!mr) {
            return RestResponse.fail("修改保养单失败，请稍后重试");
        }
        //清除超期
        MaintenancePlan plan = maintenancePlanService.getById(entity.getMtPlanId());
        if (Objects.isNull(plan)) {
            return RestResponse.success(true);
        }
        plan.setStatus(1);
        plan.setWorkDate(LocalDateTime.now());
        boolean mp = maintenancePlanService.updateById(plan);
        if (mp) {
            return RestResponse.success(true);
        } else {
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("修改维保计划失败，请稍后重试");
        }
    }

    /**
     * 维保记录评价，同时更新维保记录状态 status -> 3
     *
     * @param record MaintenanceRecord
     * @param entity Evaluation
     * @return boolean
     * @author wcz
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse evaluate(MaintenanceRecord record, Evaluation entity) {
        boolean ev = evaluationService.save(entity);
        if (!ev) {
            return RestResponse.fail("添加评价失败，请稍后重试");
        }
        boolean mr = updateById(record);
        if (mr) {
            return RestResponse.success(true);
        } else {
            //强制手动事务回滚
            rollback();
            return RestResponse.fail("更新维保记录失败，请稍后重试");
        }
    }

    /**
     * 删除维保收费项，汇总金额，拼接sparepart
     *
     * @param record       MaintenanceRecord
     * @param mtRecordCost MtRecordCost
     * @return boolean
     * @author wcz
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResponse deleteCost(MaintenanceRecord record, MtRecordCost mtRecordCost) {
        BigDecimal partsCost = mtRecordCost.getPartsCost();
        BigDecimal manCost = mtRecordCost.getManCost();
        String sparepart = mtRecordCost.getSparepart();
        if (partsCost.compareTo(BigDecimal.ZERO) > 0) {
            record.setPartsCost(record.getPartsCost().subtract(partsCost));
        }
        if (manCost.compareTo(BigDecimal.ZERO) > 0) {
            record.setManCost(record.getManCost().subtract(manCost));
        }
        if (StrUtil.isNotEmpty(sparepart)) {
            record.setSparepart(record.getSparepart().replace(sparepart + ";", ""));
        }
        boolean cost = mtRecordCostService.removeById(mtRecordCost.getId());
        if (!cost) {
            return RestResponse.fail("删除收费项失败，请稍后重试");
        }
        boolean re = updateById(record);
        if (re) {
            return RestResponse.success(true);
        } else {
            rollback();
            return RestResponse.fail("更新维保记录失败，请稍后重试");
        }
    }

    public IPage<MtRecordResponse> pageByLift(MtRecordRequest request) {
        return baseMapper.pageByLift(request.getPage(), request);
    }

    public void export(MtRecordRequest mtRecordRequest, HttpServletResponse response) {
        Map<String, String> headerAlias = new LinkedHashMap<>();
        headerAlias.put("projectName", "项目名称");
        headerAlias.put("useCompanyCode", "梯号");
        headerAlias.put("registrationCode", "注册代码");
        headerAlias.put("planDate", "计划日期");
        headerAlias.put("workDate", "执行日期");
        headerAlias.put("typeStr", "维保类型");
        headerAlias.put("hasEvaluateStr", "评价状态");
        headerAlias.put("maintenanceAdvice", "保养建议");
        headerAlias.put("workerName", "维保工");
        headerAlias.put("repairDuration", "保养时长");
        log.info("headerAlias: {}", headerAlias);

        //根据id列表查询
        List<MtRecordResponse> mtRecordResponses = new ArrayList<>();
        String[] recordIdArray = mtRecordRequest.getRecordIds().split(",");
        for (String recordIdStr : recordIdArray) {
            long recordId = Long.parseLong(recordIdStr);
            mtRecordRequest.setId(recordId);
            MtRecordResponse mtRecordResponse = getMtRecordResponse(mtRecordRequest);
            mtRecordResponses.add(mtRecordResponse);
        }
        Validate.notNull(mtRecordResponses, ValuePool.MAINTENANCE_RECORD_NOT_EXIST);
        //压缩文件夹
        File baseDir = null;
        File zipFile = null;
        try {
            //获取根目录
            String root = ValuePool.SYSTEM_USER_DIR + File.separator + "maintenance";
            String generateCode = DateUtils.generateCode();
            String dir = root + File.separator + generateCode;
            String zip = dir + ".zip";
            baseDir = new File(dir);
            zipFile = new File(zip);
            log.info("dir: {}", dir);
            log.info("zip: {}", zip);

            //生成excel文件
            String excel = File.separator + dir + File.separator + generateCode + ".xlsx";
            log.info("生成excel: {}", excel);
            File excelFile = new File(excel);
            ExcelWriter writer = ExcelUtil.getBigWriter(excelFile, "维保记录表");
            //设置列别名
            headerAlias.forEach(writer::addHeaderAlias);
            //如果为true，则不设置alias的字段将不被输出，false表示原样输出
            writer.setOnlyAlias(true);
            writer.autoSizeColumnAll();
            writer.write(mtRecordResponses, true);
            writer.close();
            FileUtil.touch(excelFile);

            //处理图片类文件
            //windows现在已知的文件名非法字符有 \ / : * ? " < > |
            String illegalChars = "\\/:*?\"<>|";
            for (int i = 0; i < mtRecordResponses.size(); i++) {
                MtRecordResponse mtRecordResponse = mtRecordResponses.get(i);
                List<MtRecordImg> mtRecordImgs = mtRecordResponse.getMtRecordImgs();
                log.info("repair: {}", mtRecordResponse);
                //处理文件夹路径
                String projectName = mtRecordResponse.getProjectName();
                String registrationCode = mtRecordResponse.getRegistrationCode();
                projectName = StrUtil.isNotEmpty(projectName) ? projectName.replace(illegalChars, "-") : "[项目]";
                registrationCode = StrUtil.isNotEmpty(registrationCode) ? registrationCode.replace(illegalChars, "-") : "[电梯注册代码]";
                //图片文件夹 dir/i.AreaName-ProjectName-RegistrationCode/
                String imgDir = StrUtil.format("{}{}{}.{}-{}{}", dir, File.separator, (i + 1), projectName, registrationCode, File.separator);

                List<MtRecordImg> imgs = mtRecordImgs.stream().filter(img -> mtRecordResponse.getId().equals(img.getMtRecordId())).collect(Collectors.toList());
                if (IterUtil.isNotEmpty(imgs)) {
                    for (int n = 0; n < imgs.size(); n++) {
                        String imgUrl = imgs.get(n).getImgUrl();
                        if (StrUtil.isNotEmpty(imgUrl)) {
                            log.info("imgUrl: {}", imgUrl);
                            String filename = imgDir + StrUtil.format("维保图片{}.jpg", (n + 1));
                            log.info("生成维保图片文件: {}", filename);
                            HttpUtil.downloadFile(imgUrl, filename);
                        }
                    }
                }
                String maintenanceExcelDir = imgDir + "1.保养单.xlsx";
                log.info("生成保养单: {}", maintenanceExcelDir);
                excelWriter(mtRecordResponse, maintenanceExcelDir);
            }

            //压缩文件夹
            log.info("生成zipfile: {}", zip);
            ZipUtil.zip(dir, zip);
        } catch (Exception e) {
            FileUtil.del(zipFile);
            FileUtil.del(baseDir);
            log.error("生成保养文件失败", e);
            throw Validate.validateException("生成保养文件失败");
        }
        //下载压缩文件
        if (FileUtil.exist(zipFile)) {
            // 设置强制下载不打开, ZIP的application/x-zip-compressed
            response.setContentType("application/force-download");
            // 设置文件名
            response.addHeader("Content-Disposition", "attachment;fileName=" + zipFile.getName());
            byte[] buffer = new byte[1024];
            try (FileInputStream fis = new FileInputStream(zipFile);
                 BufferedInputStream bis = new BufferedInputStream(fis)) {
                OutputStream os = response.getOutputStream();
                int i;
                while ((i = bis.read(buffer)) != -1) {
                    os.write(buffer, 0, i);
                }
            } catch (Exception e) {
                log.error("下载保养文件失败", e);
                throw Validate.validateException("下载保养文件失败");
            } finally {
                //删除临时根目录和zip文件
                FileUtil.del(zipFile);
                FileUtil.del(baseDir);
            }
        }
    }

    private MtRecordResponse getMtRecordResponse(@RequestBody @Val MtRecordRequest request) {
        MtRecordResponse entity = this.infoById(request);
        String repairDuration = this.getRepairDuration(entity.getRepairDiff());
        entity.setRepairDuration(repairDuration);
        Validate.notNull(entity, ValuePool.MAINTENANCE_RECORD_NOT_EXIST);
        /**
         * 维保项id:0/1/2, 0:无需保养，1：已保养，2：需要更换
         * 保养项目  用键值对的方式存储，如(1:0,2:1,3:1...)
         */
        String maintenanceOption = entity.getMaintenanceOption();
        if (StrUtil.isNotEmpty(maintenanceOption)) {
            Map<String, String> opts = Splitter.on(ValuePool.COMMA).withKeyValueSeparator(ValuePool.COLON).split(maintenanceOption);
            Map<Long, Integer> optMap = new HashMap<>();
            opts.forEach((key, value) -> {
                optMap.put(Long.parseLong(key.trim()), Integer.parseInt(value.trim()));
            });
            Collection<MaintenanceOption> mtOptions = maintenanceOptionService.listByIds(optMap.keySet());
            mtOptions.forEach(option -> {
                option.setOpt(optMap.get(option.getId()));
            });
            entity.setMtOptions(mtOptions);
        }
        Long id = request.getId();
        //查询费用项
        entity.setMtRecordCosts(mtRecordCostService.listByRecord(id));
        //查询图片
        entity.setMtRecordImgs(mtRecordImgService.listByRecord(id));
        //评价
        entity.setEvaluation(evaluationService.findByRecord(id, ValuePool.EVALUATE_SOURCE_MAINTENANCE));
        return entity;
    }

    private void excelWriter(MtRecordResponse mtRecordResponse, String maintenanceExcelDir) throws FileNotFoundException {
        HSSFWorkbook wb = new HSSFWorkbook();
        ExcelWriter writer = new ExcelWriter(wb, "保养单");

        writer.setColumnWidth(1, 25);
        writer.setColumnWidth(3, 25);
        writer.setColumnWidth(4, 25);
        writer.merge(0, 0, 0, 5, mtRecordResponse.getProjectName(), false);
        writer.merge(1, 1, 0, 1, mtRecordResponse.getCategoryStr() + "保养单", false);
        writer.merge(1, 1, 2, 3, "单号：" + mtRecordResponse.getId(), false);
        writer.merge(1, 1, 4, 5, "设备编号：" + mtRecordResponse.getUseCompanyCode(), false);
        writer.merge(2, 2, 0, 1, "注册代码：" + mtRecordResponse.getRegistrationCode(), false);
        writer.merge(2, 2, 2, 3, "电梯位置：" + mtRecordResponse.getDevicePosition(), false);
        writer.merge(2, 2, 4, 5, "保养类型：" + mtRecordResponse.getType(), false);
        writer.merge(3, 3, 0, 1, "保养时间：" + mtRecordResponse.getWorkDate().toString().replace("T"," "), false);
        writer.merge(3, 3, 2, 3, "项目编号：" + mtRecordResponse.getProjectCode(), false);
        writer.merge(3, 3, 4, 5, "项目名称：" + mtRecordResponse.getProjectName(), false);
        writer.merge(4, 4, 0, 1, "计划保养时间：" + mtRecordResponse.getPlanDate(), false);
        writer.merge(4, 4, 2, 3, "停梯时间：" + mtRecordResponse.getStopDate().toString().replace("T"," "), false);
        writer.merge(4, 4, 4, 5, "恢梯时间：" + mtRecordResponse.getRecoveryDate().toString().replace("T"," "), false);
        writer.writeCellValue(0, 5, "保养时长");
        writer.merge(5, 5, 1, 5, mtRecordResponse.getRepairDuration(), false);
        writer.writeCellValue(0, 6, "序号");
        writer.merge(6, 6, 1, 2, "维保项目", false);
        writer.merge(6, 6, 3, 4, "维保基本要求", false);
        writer.writeCellValue(5, 6, "结果");
        Collection<MaintenanceOption> mtOptions = mtRecordResponse.getMtOptions();
        int i = 0;
        for (MaintenanceOption mtOption : mtOptions) {
            i++;
            writer.writeCellValue(0, 6 + i, i);
            writer.merge(6 + i, 6 + i, 1, 2, mtOption.getItem(), false);
            writer.merge(6 + i, 6 + i, 3, 4, mtOption.getContent(), false);
            String maintenance = "√";
            switch (mtOption.getOpt()) {
                case 0:
                    maintenance = "/";
                    break;
                case 2:
                    maintenance = "X";
                    break;
            }
            writer.writeCellValue(5, 6 + i, maintenance);
        }
        writer.writeCellValue(0, 7 + i, "保养建议");
        writer.merge(7 + i, 7 + i, 1, 2, mtRecordResponse.getMaintenanceAdvice() != null ? mtRecordResponse.getMaintenanceAdvice() : "", false);
        writer.writeCellValue(3, 7 + i, "客户意见");
        String advice = "";
        if (mtRecordResponse.getEvaluation() != null) {
            if (mtRecordResponse.getEvaluation().getAdvice() != null) {
                advice = mtRecordResponse.getEvaluation().getAdvice();
            }
        }
        writer.merge(7 + i, 7 + i, 4, 5, advice, false);
        writer.writeCellValue(0, 8 + i, "工作标记");
        writer.merge(8 + i, 8 + i, 1, 5, "√：已保养项 / ：无需保养项 ×：需修理项目", false);
        writer.writeCellValue(0, 9 + i, "配件费");
        writer.merge(9 + i, 9 + i, 1, 2, mtRecordResponse.getPartsCost() != null ? mtRecordResponse.getPartsCost() : "", false);
        writer.writeCellValue(3, 9 + i, "更换配件");
        writer.merge(9 + i, 9 + i, 4, 5, mtRecordResponse.getSparepart() != null ? mtRecordResponse.getSparepart() : "", false);
        writer.writeCellValue(0, 10 + i, "维保人员");
        writer.merge(10 + i, 10 + i, 1, 2, mtRecordResponse.getWorkerName(), false);
        writer.writeCellValue(3, 10 + i, "工时费");
        writer.merge(10 + i, 10 + i, 4, 5, mtRecordResponse.getManCost() != null ? mtRecordResponse.getManCost() : "", false);
        writer.writeCellValue(0, 11 + i, "服务态度");
        StringBuilder level = new StringBuilder();
        if (mtRecordResponse.getEvaluation() != null) {
            int levelInt = mtRecordResponse.getEvaluation().getServiceLevel();
            for (int i1 = 0; i1 < levelInt; i1++) {
                level.append("★");
            }
        }
        writer.merge(11 + i, 11 + i, 1, 2, level.toString(), false);
        level = new StringBuilder();
        writer.writeCellValue(3, 11 + i, "维保质量");
        int levelInt = mtRecordResponse.getStarLevel();
        for (int i1 = 0; i1 < levelInt; i1++) {
            level.append("★");
        }
        writer.merge(11 + i, 11 + i, 4, 5, level.toString(), false);
        writer.merge(12 + i, 18 + i, 0, 0, "维保签名", false);
        writer.merge(12 + i, 18 + i, 1, 2, "", false);
        writer.merge(12 + i, 18 + i, 3, 3, "客户签名", false);
        writer.merge(12 + i, 18 + i, 4, 5, "", false);
        signImg(mtRecordResponse, wb, writer, 12 + i);
        writer.flush(new FileOutputStream(new File(maintenanceExcelDir)), true).close();
    }

    private void signImg(MtRecordResponse mtRecordResponse, HSSFWorkbook wb, ExcelWriter writer, int row) {
        Drawing<?> patriarch = writer.getSheet().createDrawingPatriarch();

        byte[] worker1Sign;
        byte[] worker2Sign;
        byte[] propertySign;
        String signatureImg1Url = mtRecordResponse.getSignatureImg1();
        String signatureImg2Url = mtRecordResponse.getSignatureImg2();
        String imgUrl = mtRecordResponse.getEvaluation() != null ? mtRecordResponse.getEvaluation().getImgUrl() : null;
        HSSFClientAnchor worker1Anchor;
        HSSFClientAnchor worker2Anchor;
        HSSFClientAnchor propertyAnchor;
        Integer workerSign1Index;
        Integer workerSign2Index;
        Integer propertySignIndex;
        if (signatureImg1Url != null && !"".equals(signatureImg1Url)) {
            worker1Sign = getImageByte(signatureImg1Url);
            workerSign1Index = wb.addPicture(worker1Sign, Workbook.PICTURE_TYPE_JPEG);
            worker1Anchor = new HSSFClientAnchor(100, 100, 500, 255, (short) 1, row, (short) 1, row + 3);
            worker1Anchor.setAnchorType(ClientAnchor.AnchorType.byId(3));
            patriarch.createPicture(worker1Anchor, workerSign1Index);
        }
        if (signatureImg2Url != null && !"".equals(signatureImg2Url)) {
            worker2Sign = getImageByte(signatureImg2Url);
            workerSign2Index = wb.addPicture(worker2Sign, Workbook.PICTURE_TYPE_JPEG);
            worker2Anchor = new HSSFClientAnchor(800, 100, 1023, 255, (short) 1, row, (short) 2, row + 3);
            worker2Anchor.setAnchorType(ClientAnchor.AnchorType.byId(3));
            patriarch.createPicture(worker2Anchor, workerSign2Index);
        }
        if (imgUrl != null && !"".equals(imgUrl)) {
            propertySign = getImageByte(imgUrl);
            propertySignIndex = wb.addPicture(propertySign, Workbook.PICTURE_TYPE_JPEG);
            propertyAnchor = new HSSFClientAnchor(300, 100, 800, 255, (short) 4, row, (short) 4, row + 3);
            propertyAnchor.setAnchorType(ClientAnchor.AnchorType.byId(3));
            patriarch.createPicture(propertyAnchor, propertySignIndex);
        }
    }

    /**
     * 获取网络图片字节数组
     *
     * @param strUrl
     * @return
     */
    public byte[] getImageByte(String strUrl) {
        System.out.println(strUrl);
        try {
            if (!strUrl.contains("http://")) {
                strUrl = "http://" + strUrl;
            }
            URL url = new URL(strUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inStream = conn.getInputStream();//通过输入流获取图片数据
            return readInputStream(inStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从输入流中获取数据
     *
     * @param inStream 输入流
     * @return
     * @throws Exception
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }
}