package com.gci.boot.modules.vehicles.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.common.vo.Result;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.modules.driver.service.ITbDriverSignInService;
import com.gci.boot.modules.projects.entity.Projects;
import com.gci.boot.modules.projects.service.IProjectsService;
import com.gci.boot.modules.system.entity.SysDict;
import com.gci.boot.modules.system.entity.SysDictItem;
import com.gci.boot.modules.system.service.ISysDictItemService;
import com.gci.boot.modules.system.service.ISysDictService;
import com.gci.boot.modules.system.vo.DictModel;
import com.gci.boot.modules.vehicles.entity.TbAnnualInspectionInfo;
import com.gci.boot.modules.vehicles.entity.TbInsurance;
import com.gci.boot.modules.vehicles.entity.TbViolationRecord;
import com.gci.boot.modules.vehicles.mapper.TbViolationRecordMapper;
import com.gci.boot.modules.vehicles.service.ITbViolationRecordService;
import com.gci.boot.modules.vehicles.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TbViolationRecordServiceImpl extends ServiceImpl<TbViolationRecordMapper, TbViolationRecord> implements ITbViolationRecordService {

    @Autowired
    private TbViolationRecordMapper violationRecordMapper;
    @Autowired
    private ISysDictService sysDictService;
    @Autowired
    private ISysDictItemService sysDictItemService;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private ITbDriverSignInService driverSignInService;
    @Value("${failExcel}")
    private String failExcel;

    @Override
    public List<VehicleProjectVO> queryVehicleProject() {
        return violationRecordMapper.queryVehicleProject();
    }

    @Override
    public List<VehicleProjectVO> queryAllVehicle() {
        return violationRecordMapper.queryAllVehicle();
    }

    @Override
    public List<VehicleProjectVO> queryAllProject() {
        return violationRecordMapper.queryProjects(0,0);
    }

    @Override
    public MessageVO analyzeMessage(String template) {
        log.info("识别短信 {}", template);
        //模板1: 【四川交警】您的小型新能源汽车川AAP0633于2023-08-19 09:10在成都市二环路西二段与战旗东路交叉路口，被交通技术监控设备记录了『不按导向车道行驶』的违法行为。请于收到本告知之日起30日内接受处理。
        //模板2: 【成都交警】川AAP8022于2023-10-30在瑞星路与琼楼路交叉路口实施机动车通过有灯控路口时，不按所需行进方向驶入导向车道的违法行为，请三十日内到交警部门接受处理。该车有18笔违法记录未处理，请及时处理。(更多请关注蓉E行)
        MessageVO vo = new MessageVO();
        // 定义车牌号的正则表达式
        String regexPlateNumber = "[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]*";
        // 定义时间的正则表达式--模板1
        String regexTime = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}";
        // 定义地点的正则表达式--模板1
        String regexLocation = "(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2})在(.+?)，";
        //违章行为--模板1
        String regexViolationAct = "『([^』]+)』";

        Pattern patternPlateNumber = Pattern.compile(regexPlateNumber);
        Matcher matcherPlateNumber = patternPlateNumber.matcher(template);
        if (matcherPlateNumber.find()) {
            vo.setPlateNumber(matcherPlateNumber.group());
        }

        Pattern patternTime = Pattern.compile(regexTime);
        Matcher matcherTime = patternTime.matcher(template);
        if (matcherTime.find()) {
            vo.setViolationTime(matcherTime.group());
        }else{
            //时间模板2处理
            Matcher matcherTime2 = Pattern.compile("\\d{4}-\\d{2}-\\d{2}").matcher(template);
            if (matcherTime2.find()) {
                vo.setViolationTime(matcherTime2.group() + " 00:00");
            }
        }

        Pattern patternAddress = Pattern.compile(regexLocation);
        Matcher matcherAddress = patternAddress.matcher(template);
        if (matcherAddress.find()) {
            vo.setViolationAddress(matcherAddress.group(2));
        }else{
            //地点模板2处理
            Matcher matcherAddress2 = Pattern.compile("(\\d{4}-\\d{2}-\\d{2})在(.+?)实施").matcher(template);
            if (matcherAddress2.find()) {
                vo.setViolationAddress(matcherAddress2.group(2));
            }
        }

        Pattern pattern = Pattern.compile(regexViolationAct);
        Matcher matcher = pattern.matcher(template);
        if (matcher.find()) {
            String violation = matcher.group(1);
            log.info("违章行为 {}", violation);
            //查字典是否存在，没有存在的话加到字典里面去
            //违章行为字典
            List<DictModel> violationList =  sysDictService.queryDictItemsByCode("violation_behavior");
            Map<String, String> violationMap = violationList.stream().collect(Collectors.toMap(DictModel::getValue, DictModel::getText));
            String act = "";
            for (String key : violationMap.keySet()) {
                String value = violationMap.getOrDefault(key,"");
                if(StrUtil.isNotBlank(value) && violation.equals(value)){
                    act = key;
                    break;
                }
            }
            if(StrUtil.isNotBlank(act)){
                vo.setViolationAct(act);
            }else{
                vo.setIsNewBehavior(true);
                vo.setNewBehavior(violation);
            }
        }else{
            //违章行为模板2处理
            Matcher matcher2 = Pattern.compile("实施(.+?)的违法行为").matcher(template);
            if (matcher2.find()) {
                String violation = matcher2.group(1);
                log.info("违章行为 {}", violation);
                //查字典是否存在，没有存在的话加到字典里面去
                //违章行为字典
                List<DictModel> violationList =  sysDictService.queryDictItemsByCode("violation_behavior");
                Map<String, String> violationMap = violationList.stream().collect(Collectors.toMap(DictModel::getValue, DictModel::getText));
                String act = "";
                for (String key : violationMap.keySet()) {
                    String value = violationMap.getOrDefault(key,"");
                    if(StrUtil.isNotBlank(value) && violation.equals(value)){
                        act = key;
                        break;
                    }
                }
                if(StrUtil.isNotBlank(act)){
                    vo.setViolationAct(act);
                }else{
                    vo.setIsNewBehavior(true);
                    vo.setNewBehavior(violation);
                }
            }else{
                vo.setIsNewBehavior(null);
            }
        }

        return vo;
    }

    @Override
    public String addViolationBehavior(MessageVO vo) {
        //违章行为字典
        List<DictModel> violationList =  sysDictService.queryDictItemsByCode("violation_behavior");
        List<String> distTexts = violationList.stream().map(DictModel::getText).collect(Collectors.toList());
        if(distTexts.contains(vo.getNewBehavior())){
            return "已存在该违章行为!";
        }
        //保存到字典
       LambdaQueryWrapper<SysDict> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.eq(SysDict::getDictCode,"violation_behavior").last(" limit 1 ");
       SysDict sysDict = sysDictService.getOne(queryWrapper);

       SysDictItem dictItem = new SysDictItem();
       dictItem.setDictId(sysDict.getId());
       dictItem.setItemText(vo.getNewBehavior());
       dictItem.setItemValue(String.valueOf(getMaxValue(violationList)));
       dictItem.setStatus(1);
       sysDictItemService.save(dictItem);
       return dictItem.getItemValue();
    }

    @Override
    public List<MsgImportFailVO> importViolationMessage(List<String> msgTemplates) {
        if(CollectionUtil.isEmpty(msgTemplates)){
            return null;
        }
        List<MsgImportFailVO> failList = new ArrayList<>();
        //查用户所有权限车牌
        List<String> plateNumbers = projectsService.queryAllPlateNumberListOfUser();
        //查项目车牌对应
        List<VehicleProjectVO> projectCarList = this.queryVehicleProject();
        List<String> carList = projectCarList.stream().map(VehicleProjectVO::getPlateNumber).collect(Collectors.toList());
        //查是否有重复
        Map<String, List<Integer>> repeatMap = getRepeatIndex(msgTemplates);
        //历史记录
        List<TbViolationRecord> historyList = this.list();
        for(int i = 0; i< msgTemplates.size(); i++){
            int flag = 0;
            String failDetails = "";
            MsgImportFailVO failVO = new MsgImportFailVO();
            MessageVO vo = this.analyzeMessage(msgTemplates.get(i));
            if(StrUtil.isBlank(vo.getPlateNumber())){
                flag += 1;
                failDetails += "'车牌号' 解析为空 ";
                failVO.setFormatErrors("1");
            }
            if(StrUtil.isBlank(vo.getViolationAddress())){
                flag += 1;
                failDetails += "'违章地点' 解析为空 ";
                failVO.setFormatErrors("1");
            }
            if((StrUtil.isBlank(vo.getViolationAct()) && StrUtil.isBlank(vo.getNewBehavior()))){
                flag += 1;
                failDetails += "'违章行为' 解析为空 ";
                failVO.setFormatErrors("1");
            }
            if(StrUtil.isBlank(vo.getViolationTime())){
                flag += 1;
                failDetails += "'违章时间' 解析为空 ";
                failVO.setFormatErrors("1");
            }

            if(!plateNumbers.contains(vo.getPlateNumber())){
                flag += 1;
                failDetails += "当前用户没有该车牌号权限或车辆不存在 ";
                failVO.setFormatErrors("1");
            }
            if(Objects.nonNull(vo.getIsNewBehavior()) && vo.getIsNewBehavior()){
                flag += 1;
                failDetails += "该违章行为缺少对应字典 ";
                failVO.setFormatErrors("1");
            }
            if(!carList.contains(vo.getPlateNumber())){
                flag += 1;
                failDetails += "该车牌号没有对应项目 ";
                failVO.setFormatErrors("1");
            }
            if(Objects.nonNull(repeatMap) && repeatMap.containsKey(msgTemplates.get(i))){
                flag += 1;
                failDetails += "存在重复的'违章短信' ";
                failVO.setRepeatErrors("1");
            }
            if(StrUtil.isNotBlank(vo.getPlateNumber()) && StrUtil.isNotBlank(vo.getViolationAct()) && StrUtil.isNotBlank(vo.getViolationTime())){
                //判断是否与历史数据重复
                List<TbViolationRecord> historys = historyList.stream().filter(h -> vo.getPlateNumber().equals(h.getPlateNumber())
                        && vo.getViolationAct().equals(h.getViolationAct())
                        && vo.getViolationTime().equals(DateUtil.format(h.getViolationTime(),"yyyy-MM-dd HH:mm"))).collect(Collectors.toList());
                if(CollectionUtil.isNotEmpty(historys)){
                    flag += 1;
                    failDetails += "'车牌号'、'违章行为'、'违章时间'已存在重复历史记录 ";
                    failVO.setRepeatErrors("1");
                }
            }
            if(flag > 0){
                //记录失败数据及原因
                failVO.setMsg(msgTemplates.get(i));
                failVO.setFailDetails(failDetails);
                failList.add(failVO);
            }else{
                try {
                    //保存
                    TbViolationRecord violationRecord = new TbViolationRecord();
                    violationRecord.setPlateNumber(vo.getPlateNumber());
                    //项目、负责人
                    VehicleProjectVO projectCar = projectCarList.stream().filter(item -> item.getPlateNumber().equals(vo.getPlateNumber())).findFirst().orElse(null);
                    if(Objects.nonNull(projectCar)){
                        violationRecord.setProjectId(projectCar.getProjectId());
                        violationRecord.setDirector(projectCar.getProjectManager());
                    }
                    Projects projects = projectsService.getById(violationRecord.getProjectId());
                    if(Objects.nonNull(projects)){
                        violationRecord.setProjectName(projects.getProjectName());
                    }
                    //违章行为、地点、时间
                    violationRecord.setViolationAct(vo.getViolationAct());
                    violationRecord.setViolationAddress(vo.getViolationAddress());
                    violationRecord.setViolationTime(DateUtil.parse(vo.getViolationTime(),"yyyy-MM-dd HH:mm"));
                    //司机
                    violationRecord.setViolationDriver(driverSignInService.queryDriverByPlateNumberAndTime(vo.getPlateNumber(),vo.getViolationTime()));
                    this.save(violationRecord);
                }catch (Exception e){
                    e.printStackTrace();
                    //记录保存异常数据
                    MsgImportFailVO newFailVO = new MsgImportFailVO();
                    newFailVO.setMsg(msgTemplates.get(i));
                    newFailVO.setFailDetails(e.getMessage());
                    newFailVO.setFormatErrors("1");
                    failList.add(newFailVO);
                }
            }
        }
        return failList;
    }

    //已导入xx条；第x、a、y行数据重复，第xx、aa行数据格式异常。
    @Override
    public Result<?> msgImport(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        int size = 0;
        try {
//            List<String> dataList = this.readSingleColumnFromExcel(inputStream);
            List<String> dataList = new ArrayList<>();
            List<MsgImportFailVO> list = EasyExcel.read(inputStream).head(MsgImportFailVO.class).sheet().doReadSync();
            if(CollectionUtils.isEmpty(list)){
                return Result.error("导入违章短信数据不能为空！请检查导入模板!");
            }
            dataList = list.stream().filter(s->StrUtil.isNotBlank(s.getMsg())).map(MsgImportFailVO::getMsg).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(dataList)){
                return Result.error("导入违章短信数据不能为空！请检查导入模板!");
            }
            size = dataList.size();
            List<MsgImportFailVO> failList = this.importViolationMessage(dataList);
            if (CollectionUtil.isNotEmpty(failList)) {
                String fielName = System.currentTimeMillis() + CommonConstant.VIOLATE_IMPORT_FAIL_EXCEL_NAME;
                EasyExcel.write(failExcel + fielName, MsgImportFailVO.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("导入异常数据").doWrite(failList);
                JSONObject entries = new JSONObject();
                //格式异常行数
//                List<Integer> indexes = new ArrayList<>();
//                for (int i = 0; i < failList.size(); i++) {
//                    if ("1".equals(failList.get(i).getFormatErrors())) {
//                        indexes.add(i+2);
//                    }
//                }
//                //数据重复
//                List<Integer> repeatIndexes = new ArrayList<>();
//                for (int i = 0; i < failList.size(); i++) {
//                    if ("1".equals(failList.get(i).getRepeatErrors())) {
//                        repeatIndexes.add(i+2);
//                    }
//                }
                String errorMsg = "已导入"+ (size-failList.size()) + "条;失败"+ failList.size() +"条;具体失败详情见失败导出信息表";
//                if(CollectionUtil.isNotEmpty(repeatIndexes)){
//                    errorMsg += "第"+  repeatIndexes + "行数据重复;";
//                }
//                if(CollectionUtil.isNotEmpty(indexes)){
//                    errorMsg += "第"+  indexes + "行数据格式异常";
//                }
                entries.set("msg",errorMsg);
                entries.set("path",fielName);
                return Result.ok(entries);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("导入异常,请联系管理员!");
        } finally {
            inputStream.close();
        }
        return Result.ok();
    }


    public int getMaxValue(List<DictModel> violationList) {
        int maxValue = Integer.MIN_VALUE;
        for (DictModel dictModel : violationList) {
            String valueStr = dictModel.getValue();
            int value = Integer.parseInt(valueStr);
            if (value > maxValue) {
                maxValue = value;
            }
        }
        return maxValue + 1;
    }

    /**
     *读Excel
     */
    public List<String> readSingleColumnFromExcel(InputStream inputStream) throws IOException {
        List<String> dataList = new ArrayList<>();
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);
        int rowCount = sheet.getLastRowNum(); // 获取最后一行的索引
        for (int i = 1; i <= rowCount; i++) { // 从第二行开始读取数据
            Row row = sheet.getRow(i);
            if(Objects.nonNull(row)){
                Cell cell = row.getCell(0);
                if (cell != null) {
                    String cellValue = getCellValueAsString(cell);
                    if (!cellValue.isEmpty() && !cellValue.trim().isEmpty()) { // 校验单元格内容非空
                        dataList.add(cellValue);
                    }
                }
            }
        }
        workbook.close();
        return dataList;
    }
    private String getCellValueAsString(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case BLANK:
                return "";
            default:
                return "";
        }
    }

    /**
     * 获取重复的导入数据索引,按重复短信进行分组
     */
    public Map<String, List<Integer>> getRepeatIndex(List<String> msgTemplates) {
        if(CollectionUtil.isEmpty(msgTemplates)){
            return null;
        }
        Map<String, List<Integer>> indexMap = new HashMap<>();
        for (int i = 0; i < msgTemplates.size(); i++) {
            String msg = msgTemplates.get(i);
            if (indexMap.containsKey(msg)) {
                indexMap.get(msg).add(i+1);
            } else {
                List<Integer> indexes = new ArrayList<>();
                indexes.add(i+1);
                indexMap.put(msg, indexes);
            }
        }
        //删除不重复的记录
        List<String> keysToRemove = new ArrayList<>();
        for (Map.Entry<String, List<Integer>> entry : indexMap.entrySet()) {
            if (entry.getValue().size() == 1) {
                keysToRemove.add(entry.getKey());
            }
        }
        for (String key : keysToRemove) {
            indexMap.remove(key);
        }
        return indexMap;
    }
}
