package com.om.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.om.entity.dto.*;
import com.om.entity.po.*;
import com.om.entity.po.VciInfo;
import com.om.entity.vo.*;
import com.om.exception.BadReqException;
import com.om.exception.BizException;
import com.om.mapper.RepairMapper;
import com.om.mapper.VciInfoMapper;
import com.om.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.om.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author bmmx
 * @since 2024-02-18
 */
@Service
public class RepairServiceImpl extends ServiceImpl<RepairMapper, Repair> implements IRepairService {

    @Resource
    private IFaultCodeService faultCodeService;

    @Resource
    private IEcuInfoService ecuInfoService;

    @Resource
    private IElectronicControlService electronicControlService;

    @Resource
    RepairMapper repairMapper;

    @Resource
    IUserService userService;

    @Resource
    private HuaweiObsUtil huaweiObsUtil;

    @Resource
    private HttpServletRequest request;

    @Resource
    private ITextPdfUtil pdfUtil;

    @Resource
    private HtmlGenerator htmlGenerator;

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private IUserVciService userVciService;
    @Resource
    private VciInfoMapper vciInfoMapper;

    @Override
    @Transactional
    public Result AppCreateReport(APPReportCreateDTO dto) {
        String guid = dto.getGuid();
        GuidDTO guidDTO = AesUtil.getGuidDTOFromGuid(guid);
        Integer userId = guidDTO.getUserId();
        User user = userService.getById(userId);
        // 判断数据、
        if (BeanUtil.isEmpty(dto)) {
            return Result.fail("未获取到数据").result(ResultCode.NO_DATA);
        }

        Repair repair = BeanUtil.copyProperties(dto, Repair.class);
        repair.setUsername(user.getUsername());
        repair.setStatus(1);
        repair.setCreateTime(LocalDateTime.now());
        repair.setUpdateTime(LocalDateTime.now());
        //报告编号

        this.save(repair);
        String yyMMdd = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
        String repairNum = yyMMdd + repair.getId() + RandomUtil.randomNumbers(5);
        repair.setRepairNum(repairNum);
        this.updateById(repair);
        List<AppElectronicDTO> electronicControls = dto.getElectronicControls();

        List<Integer> eleIds = new ArrayList<>();
        List<ElectronicControl> electronicControlList = new ArrayList<>();
        for (AppElectronicDTO electronicControlDTO : electronicControls) {

            ElectronicControl electronicControl = new ElectronicControl();
            electronicControl.setElectronicControlName(electronicControlDTO.getElectronicControlName());
            electronicControl.setRepairId(repair.getId());

            electronicControlService.save(electronicControl);

            electronicControlList.add(electronicControl);
            List<AppEcuInfoDTO> ecuInfors = electronicControlDTO.getEcuInfors();
            List<AppFaultCodeDTO> faultCodes = electronicControlDTO.getFaultCodes();

            List<EcuInfo> ecuInfos = BeanUtil.copyToList(ecuInfors, EcuInfo.class);
            List<FaultCode> faultCodes1 = BeanUtil.copyToList(faultCodes, FaultCode.class);

            for (EcuInfo ecuInfo : ecuInfos) {
                ecuInfo.setElectronicControlId(electronicControl.getId());
            }

            for (FaultCode faultCode : faultCodes1) {
                faultCode.setElectronicControlId(electronicControl.getId());
                faultCode.setStatus(1);
            }

            eleIds.add(electronicControl.getId());

            ecuInfoService.saveBatch(ecuInfos);
            faultCodeService.saveBatch(faultCodes1);
        }


        return Result.ok();
    }

    @Override
    public Result AppGetPageList(APPRepairQueryPageDTO dto) {
        String guid = dto.getGuid();
        GuidDTO guidDTO = AesUtil.getGuidDTOFromGuid(guid);
        Integer userId = guidDTO.getUserId();
        String deviceSn = guidDTO.getDeviceSn();
        String searchVciSn = dto.getSearchVciSn();
        User user = userService.getById(userId);
        if (BeanUtil.isEmpty(user)) {
            return Result.fail("用户不存在").result(ResultCode.NO_DATA);
        }

        UserVci userVci = userVciService.lambdaQuery()
                .eq(UserVci::getUserId, userId)
                .eq(UserVci::getIsDefault, 1)
                .one();

        VciInfo vciInfo = vciInfoMapper.selectById(userVci.getVciInfoId());

        AppRepairQueryPageVO vo = new AppRepairQueryPageVO();
        //获取数据
        Integer pageIndex = dto.getPageIndex();
        Integer pageSize = dto.getPageSize();
        List<Repair> records = new ArrayList<>();
        if (pageIndex == 0 && pageSize == 0) {
            records = this.lambdaQuery()
                    .eq(Repair::getSn, vciInfo.getVciNum())
                    .orderByDesc(Repair::getCreateTime)
                    .list();
            if (records.isEmpty()) {
                return Result.ok(vo);
            }
            vo.setTotal(records.size());
        } else {
            //分页查询
            Page<Repair> page = this.lambdaQuery()
                    .eq(Repair::getSn, vciInfo.getVciNum())
                    .orderByDesc(Repair::getCreateTime)
                    .page(new Page<>(pageIndex, pageSize));

            if (page.getRecords().isEmpty()) {
                return Result.ok(vo);
            }

            vo.setSize(pageSize);
            vo.setCurrent(pageIndex);
            vo.setPages((int) page.getPages());
            vo.setTotal((int) page.getTotal());

            records = page.getRecords();
        }
        if (CollectionUtil.isEmpty(records)) {
            records = Collections.emptyList();
        }

        List<DiagnosticReportVO> list = new ArrayList<>();
        for (Repair record : records) {
            DiagnosticReportVO diagnosticReportVO = new DiagnosticReportVO();
            diagnosticReportVO.setCreationTime(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
            diagnosticReportVO.setDiagnosticReportId(record.getId());
            diagnosticReportVO.setDiagnosticReportName(record.getFileName());
            diagnosticReportVO.setFileName(record.getFileName());
            diagnosticReportVO.setVciSn(record.getSn());

            List<Integer> eleIds = electronicControlService.lambdaQuery()
                    .eq(ElectronicControl::getRepairId, record.getId())
                    .list().stream().map(c -> c.getId()).collect(Collectors.toList());

            if (!eleIds.isEmpty()) {
                for (Integer eleId : eleIds) {
                    List<FaultCode> faultCodeList = faultCodeService.lambdaQuery()
                            .eq(FaultCode::getElectronicControlId, eleId)
                            .list();
                    if (!faultCodeList.isEmpty()) {
                        diagnosticReportVO.setFaultCodesNumber(String.valueOf(faultCodeList.size()));
                    }
                }
            }
            list.add(diagnosticReportVO);
        }

        vo.setRecords(list);
        return Result.ok(vo);
    }


    @Override
    @Transactional
    public Result create(RepairDTO repairDTO) {
        Repair repair = new Repair();
        BeanUtil.copyProperties(repairDTO, repair);
        return Result.ok();
    }

    @Override
    @Transactional
    public Result delete(AppBaseDTO dto) {
        Integer id = dto.getDiagnosticReportId();
        Repair repair = this.getById(id);
        if (repair == null) {
            throw new BadReqException("该诊断报告不存在");
        }

        List<Integer> eleIds = electronicControlService.lambdaQuery()
                .eq(ElectronicControl::getRepairId, repair.getId())
                .list().stream().map(c -> c.getId()).collect(Collectors.toList());
        if (!eleIds.isEmpty()) {
            for (Integer eleId : eleIds) {
                List<Integer> faultIds = faultCodeService.lambdaQuery()
                        .eq(FaultCode::getElectronicControlId, eleId)
                        .list().stream().map(c -> c.getId()).collect(Collectors.toList());

                List<Integer> ecuIds = ecuInfoService.lambdaQuery()
                        .eq(EcuInfo::getElectronicControlId, eleId)
                        .list().stream().map(c -> c.getId()).collect(Collectors.toList());

                faultCodeService.removeByIds(faultIds);
                ecuInfoService.removeByIds(ecuIds);
            }
            electronicControlService.removeByIds(eleIds);
        }

        this.removeById(id);
        return Result.ok();
    }

    @Override
    public Result<RepairVO> getByIds(Integer id) {
        Repair repair = this.getById(id);
        if (repair == null) {
            throw new BadReqException("该诊断报告不存在");
        }

        RepairVO vo = new RepairVO();
        List<Integer> eleIds = electronicControlService.lambdaQuery()
                .eq(ElectronicControl::getRepairId, repair.getId())
                .list().stream().map(c -> c.getId()).collect(Collectors.toList());

        BeanUtil.copyProperties(repair, vo);
        ReportTitleDto reportTitleDto = new ReportTitleDto();
        BeanUtil.copyProperties(repair, reportTitleDto);

        List<ElectronicControls> electronicControlsList = new ArrayList<>();
        int eleCount = 0;
        int faultCount = 0;
        if (!eleIds.isEmpty()) {
            for (Integer eleId : eleIds) {
                ElectronicControls electronicControls = new ElectronicControls();
                ElectronicControl electronicControl = electronicControlService.getById(eleId);

                BeanUtil.copyProperties(electronicControl, reportTitleDto);
                electronicControls.setElectronicControlName(electronicControl.getElectronicControlName());

                List<EcuInfo> list = ecuInfoService.lambdaQuery()
                        .eq(EcuInfo::getElectronicControlId, eleId)
                        .list();
                electronicControls.setEcuInfo(list);

                List<FaultCode> faultCodeList = faultCodeService.lambdaQuery()
                        .eq(FaultCode::getElectronicControlId, eleId)
                        .list();
                electronicControls.setFaultCode(faultCodeList);

                electronicControlsList.add(electronicControls);
                eleCount++;
                faultCount += faultCodeList.size();
            }
        }
        vo.setElectronicControls(electronicControlsList);
        vo.setElectronicControlCount(eleCount);
        vo.setFaultCodeCount(faultCount);
        vo.setReportTitleDto(reportTitleDto);

        return Result.ok();
    }

    @Override
    public Result<RepairQueryPageVO> getPageList(RepairQueryPageDTO dto) {

        //从dto中获取数据
        Integer pageIndex = dto.getPageIndex();
        Integer pageSize = dto.getPageSize();
        LocalDateTime beginTime = dto.getBeginTime();
        LocalDateTime endTime = dto.getEndTime();
        String searchNum = dto.getSearchNum();
        String searchVIN = dto.getSearchVIN();
        String searchDistributor = dto.getSearchDistributor();

        //分页查询
        Page<Repair> page = this.lambdaQuery()
                .like(StringUtils.isNotBlank(searchNum), Repair::getSn, searchNum)
                .like(StringUtils.isNotBlank(searchVIN), Repair::getVin, searchVIN)
                .like(StringUtils.isNotBlank(searchDistributor), Repair::getDepartmentName, searchDistributor)
                .ge(beginTime != null, Repair::getCreateTime, beginTime)
                .le(endTime != null, Repair::getCreateTime, endTime)
                .page(new Page<>(pageIndex, pageSize));


        RepairQueryPageVO vo = new RepairQueryPageVO();
        vo.setCurrent((int) page.getCurrent());
        vo.setSize((int) page.getSize());
        vo.setPages((int) page.getPages());
        vo.setTotal((int) page.getTotal());

        if (StringUtils.isNotBlank(searchNum) || StringUtils.isNotBlank(searchDistributor) || beginTime != null || endTime != null) {
            vo.setSearchCount(true);
        }

        List<Repair> records = page.getRecords();
        if (records.isEmpty()) {
            return Result.ok(vo);
        }

        List<QueryRepairVO> queryRepairVOList = new ArrayList<>();
        for (Repair record : records) {
            QueryRepairVO queryRepairVO = BeanUtil.copyProperties(record, QueryRepairVO.class);
            //根据Repair id 查询
            List<ElectronicControl> electronicControls = electronicControlService.lambdaQuery()
                    .eq(ElectronicControl::getRepairId, record.getId())
                    .list();
            if (!electronicControls.isEmpty()) {
                //查询系统数量
                queryRepairVO.setSystemCount(electronicControls.size());
            }

            int faultCount = 0;
            for (ElectronicControl electronicControl : electronicControls) {
                List<FaultCode> faultCodeList = faultCodeService.lambdaQuery()
                        .eq(electronicControl != null, FaultCode::getElectronicControlId, electronicControl.getId())
                        .list();

                faultCount += faultCodeList.size();
            }
            //查询故障数量
            queryRepairVO.setFaultCount(faultCount);
            queryRepairVOList.add(queryRepairVO);
        }

        vo.setRecords(queryRepairVOList);


        return Result.ok(vo);
    }

    @Override
    public Result<String> reportPdf(Integer id) {
        //根据id查询报告是否存在
        Repair repair = this.getById(id);

        if (BeanUtil.isEmpty(repair)) {
            throw new BadReqException("该诊断报告不存在");
        }

        Map<String, String> baseMap = new HashMap<>();
        baseMap.put("车架号", repair.getVin());
        baseMap.put("年款", repair.getModelYear());
        baseMap.put("里程", repair.getMileage());
        baseMap.put("诊断路径", repair.getDiagnosticPath());
        baseMap.put("报告编号", repair.getRepairNum());
        baseMap.put("SN", repair.getSn());


        Map<String, String> companyMap = new HashMap<>();
        companyMap.put("公司", repair.getCompany());
        companyMap.put("电话", repair.getTelephone());
        companyMap.put("地址", repair.getAddress());

        List<ControlListMap> controlListMap = new ArrayList<>();

        List<Integer> eleIds = electronicControlService.lambdaQuery()
                .eq(ElectronicControl::getRepairId, repair.getId())
                .list().stream().map(c -> c.getId()).collect(Collectors.toList());
        if (!eleIds.isEmpty()) {
            List<ElectronicControl> electronicControlList = electronicControlService.listByIds(eleIds);
            for (Integer eleId : eleIds) {
                ElectronicControl electronicControl = electronicControlService.getById(eleId);

                List<EcuInfo> EcuList = ecuInfoService.lambdaQuery()
                        .eq(EcuInfo::getElectronicControlId, eleId)
                        .list();

                List<FaultCode> FaultList = faultCodeService.lambdaQuery()
                        .eq(FaultCode::getElectronicControlId, eleId)
                        .eq(FaultCode::getStatus, 1)
                        .list();

                Map<String, String> faultCodeMap = new HashMap<>();
                Map<String, String> versionMap = new HashMap<>();
                for (EcuInfo ecuInfo : EcuList) {
                    versionMap.put(ecuInfo.getStrCaption(), ecuInfo.getStrInformation());
                }

                for (FaultCode faultCode : FaultList) {
                    faultCodeMap.put(faultCode.getFaultCode(), faultCode.getDescription());
                }
                ControlListMap controlListMap1 = new ControlListMap();
                controlListMap1.setName(electronicControl.getElectronicControlName());
                controlListMap1.setVersionMap(versionMap);
                controlListMap1.setFaultCodeMap(faultCodeMap);
                controlListMap.add(controlListMap1);
            }
        }

        File file = pdfUtil.MapToPDF(repair.getId(), controlListMap, baseMap, companyMap);
        if (file == null) {
            throw new BizException("该pdf文件不存在");
        }
        try {
            huaweiObsUtil.upload(file, "report");
            String uploadUrl1 = huaweiObsUtil.getUploadUrl(file.getName(), "report");
            file.delete();
            return Result.ok(uploadUrl1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result reportH5(Integer id) {
        //根据id查询报告是否存在
        Repair repair = this.getById(id);

        if (BeanUtil.isEmpty(repair)) {
            throw new BadReqException("该诊断报告不存在");
        }

        Map<String, String> baseMap = new HashMap<>();
        baseMap.put("车架号", repair.getVin());
        baseMap.put("年款", repair.getModelYear());
        baseMap.put("里程", repair.getMileage());
        baseMap.put("诊断路径", repair.getDiagnosticPath());
        baseMap.put("报告编号", repair.getRepairNum());
        baseMap.put("SN", repair.getSn());

        Map<String, String> companyMap = new HashMap<>();
        companyMap.put("公司", repair.getCompany());
        companyMap.put("电话", repair.getTelephone());
        companyMap.put("地址", repair.getAddress());

        List<ControlListMap> controlListMap = new ArrayList<>();

        List<Integer> eleIds = electronicControlService.lambdaQuery()
                .eq(ElectronicControl::getRepairId, repair.getId())
                .list().stream().map(c -> c.getId()).collect(Collectors.toList());
        if (!eleIds.isEmpty()) {
            List<ElectronicControl> electronicControlList = electronicControlService.listByIds(eleIds);
            for (Integer eleId : eleIds) {
                ElectronicControl electronicControl = electronicControlService.getById(eleId);

                List<EcuInfo> EcuList = ecuInfoService.lambdaQuery()
                        .eq(EcuInfo::getElectronicControlId, eleId)
                        .list();

                List<FaultCode> FaultList = faultCodeService.lambdaQuery()
                        .eq(FaultCode::getElectronicControlId, eleId)
                        .eq(FaultCode::getStatus, 1)
                        .list();

                Map<String, String> faultCodeMap = new HashMap<>();
                Map<String, String> versionMap = new HashMap<>();
                for (EcuInfo ecuInfo : EcuList) {
                    versionMap.put(ecuInfo.getStrCaption(), ecuInfo.getStrInformation());
                }

                for (FaultCode faultCode : FaultList) {
                    faultCodeMap.put(faultCode.getFaultCode(), faultCode.getDescription());
                }
                ControlListMap controlListMap1 = new ControlListMap();
                controlListMap1.setName(electronicControl.getElectronicControlName());
                controlListMap1.setVersionMap(versionMap);
                controlListMap1.setFaultCodeMap(faultCodeMap);
                controlListMap.add(controlListMap1);
            }
        }


        File file = htmlGenerator.generateHtmlByMap(repair.getId(), controlListMap, baseMap, companyMap);

        if (file == null) {
            throw new BizException("该h5文件不存在");
        }
        try {
            huaweiObsUtil.upload(file, "h5");

            String uploadUrl1 = huaweiObsUtil.getUploadUrl(file.getName(), "h5");
            file.delete();
            return Result.ok(uploadUrl1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result updateBase(AppRepairUpdateBaseDTO dto) {
        Integer id = dto.getId();
        String type = dto.getType();
        String value = dto.getValue();

        //根据id进行查询
        Repair repair = this.getById(id);
        if (BeanUtil.isEmpty(repair)) {
            throw new BadReqException("该诊断报告不存在");
        }

        if (type.equals("vin")) {
            repair.setVin(value);
        } else if (type.equals("year")) {
            repair.setModelYear(value);
        } else if (type.equals("mileage")) {
            repair.setMileage(value);
        }

        this.updateById(repair);
        return Result.ok();
    }

    @Override
    public Result updateCompany(AppRepairUpdateBaseDTO dto) {
        Integer id = dto.getId();
        String type = dto.getType();
        String value = dto.getValue();

        //根据id进行查询
        Repair repair = this.getById(id);
        if (BeanUtil.isEmpty(repair)) {
            throw new BadReqException("该诊断报告不存在");
        }
        String username = repair.getUsername();

        //根据username查询用户
        User user = userService.lambdaQuery()
                .eq(User::getUsername, username)
                .one();
        if (BeanUtil.isEmpty(user)) {
            return Result.fail("用户不存在").result(ResultCode.USER_NO_EXIST);
        }

        if (type.equals("company")) {
            user.setCompany(value);
        } else if (type.equals("address")) {
            user.setAddress(value);
        } else if (type.equals("phone")) {
            user.setTel(value);
        }

        userService.updateById(user);
        return Result.ok();

    }

    @Override
    public Result<String> getH5(AppBaseDTO dto) {
        String guid = dto.getGuid();
        GuidDTO guidDTO = AesUtil.getGuidDTOFromGuid(guid);
        Integer userId = guidDTO.getUserId();

        Integer diagnosticReportId = dto.getDiagnosticReportId();
        return this.reportH5(diagnosticReportId);
    }


}




