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

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.gci.boot.common.util.ValidatorUtil;
import com.gci.boot.common.vo.Result;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.modules.basedata.entity.TbInsuranceCompanyArchives;
import com.gci.boot.modules.basedata.entity.TbVehicle;
import com.gci.boot.modules.basedata.mapper.TbInsuranceCompanyArchivesMapper;
import com.gci.boot.modules.basedata.service.ITbVehicleService;
import com.gci.boot.modules.driver.vo.DriverImportVO;
import com.gci.boot.modules.projects.entity.Projects;
import com.gci.boot.modules.projects.entity.TbContract;
import com.gci.boot.modules.projects.mapper.TbContractMapper;
import com.gci.boot.modules.projects.service.IProjectsService;
import com.gci.boot.modules.projects.service.ITbContractService;
import com.gci.boot.modules.system.vo.LoginUser;
import com.gci.boot.modules.vehicles.service.ITbInsuranceRemindService;
import com.gci.boot.modules.vehicles.vo.InsuranceImportVO;
import com.gci.boot.modules.vehicles.vo.RepairImportVO;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.common.util.DateUtils;
import com.gci.boot.common.util.MinioUtils;
import com.gci.boot.enums.FileExtension;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.statis.vo.InsuranceStatisVo;
import com.gci.boot.modules.statis.vo.StatisParamVO;
import com.gci.boot.modules.vehicles.controller.TbInsuranceController;
import com.gci.boot.modules.vehicles.entity.TbInsurance;
import com.gci.boot.modules.vehicles.mapper.TbInsuranceMapper;
import com.gci.boot.modules.vehicles.service.ITbInsuranceService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

/**
 * <p>
 * 保险信息 服务实现类
 * </p>
 *
 * @author xushuhan
 * @since 2023-09-21
 */
@Slf4j
@Service
public class TbInsuranceServiceImpl extends ServiceImpl<TbInsuranceMapper, TbInsurance> implements ITbInsuranceService {

	@Autowired
    private MinioUtils minioUtils;

	@Autowired
	private IProjectsService projectsService;

	@Value("${failExcel}")
	private String failExcel;

	@Autowired
	private ITbVehicleService vehicleService;

	@Autowired
	private TbContractMapper tbContractMapper;

	@Autowired
	private TbInsuranceCompanyArchivesMapper tbInsuranceCompanyArchivesMapper;

	@Autowired
	private ITbInsuranceRemindService insuranceRemindService;

	//保险业务量报表
	@Override
	public List<InsuranceStatisVo> page(Page<InsuranceStatisVo> page, StatisParamVO vo) {
		if("1".equals(vo.getStatisType())){
			vo.setStatisTime("YYYY-MM-DD");
		}else if("2".equals(vo.getStatisType())){
			vo.setStatisTime("YYYY-MM");
		}else if("3".equals(vo.getStatisType())){
			vo.setStatisTime("YYYY");
		}else{
			vo.setStatisTime("YYYY-MM-DD");
		}
		return baseMapper.findStatisInsuranceByDayMonthYear(page, vo);
	}

	@Override
	public Map<String, TbInsurance> getLastInsurance(List<String> vids) {
		LambdaQueryWrapper<TbInsurance> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(TbInsurance::getVehicleId, vids);
		queryWrapper.orderByAsc(TbInsurance::getCompulsoryValidTime);
		List<TbInsurance> list = list(queryWrapper);
		Map<String,TbInsurance> map = new HashMap<>();
		for (TbInsurance tbInsurance : list) {
			map.put(tbInsurance.getVehicleId(), tbInsurance);
		}
		return map;
	}

	@Override
	public String checkItem(TbInsurance item) {
		String error = "";
		List<TbInsurance> list = getByVehicleId(item);
		for (TbInsurance tbInsurance : list) {
			if(DateUtils.compareTo(item.getCompulsoryValidTime(), tbInsurance.getCompulsoryValidTime())<1
					&&DateUtils.compareTo(item.getCompulsoryValidTime(), tbInsurance.getCompulsoryStartTime())>-1) {
				return "有效日期不能与已有保险交叉！";
			}
			if(DateUtils.compareTo(item.getCompulsoryStartTime(), tbInsurance.getCompulsoryValidTime())<1
					&&DateUtils.compareTo(item.getCompulsoryStartTime(), tbInsurance.getCompulsoryStartTime())>-1) {
				return "起保日期不能与已有保险交叉！";
			}
		}
		if(StringUtils.hasLength(item.getCompulsoryUrl())) {
			if(item.getCompulsoryUrl().split(",").length>10) {
				throw new GciBootException("上传交强险附件不能超过10个！");
			}
		}
		if(StringUtils.hasLength(item.getCommercialUrl())) {
			if(item.getCommercialUrl().split(",").length>10) {
				throw new GciBootException("上传商业保险附件不能超过10个！");
			}
		}
		return error;
	}

	public List<TbInsurance> getByVehicleId(TbInsurance item) {
		LambdaQueryWrapper<TbInsurance> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TbInsurance::getVehicleId, item.getVehicleId());
		queryWrapper.ne(StringUtils.hasLength(item.getId()),TbInsurance::getId, item.getId());
		List<TbInsurance> list = list(queryWrapper);
		return list;
	}

	public Map<String, TbInsurance> getInsuranceByFrameNumber() {
		LambdaQueryWrapper<TbInsurance> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.orderByAsc(TbInsurance::getCompulsoryValidTime);
		List<TbInsurance> list = list(queryWrapper);
		Map<String,TbInsurance> map = new HashMap<>();
		for (TbInsurance tbInsurance : list) {
			map.put(tbInsurance.getFrameNumber().toUpperCase(), tbInsurance);
		}
		return map;
	}

	//保险附件批量上传
	@Override
	public int uploadFiles(Map<String,File> fileMap,String hasCompulsoryInsurance) {
		int count = 0;
		List<TbInsurance> update = new ArrayList<>();
		Map<String, TbInsurance> imap = getInsuranceByFrameNumber();
		for(String key:imap.keySet()) {
			if(count==fileMap.size()) {
				break;
			}
			String urls = "";
			TbInsurance item = imap.get(key);
			for(String fkey:fileMap.keySet()) {
				File file = fileMap.get(fkey);
				if(file!=null&&fkey.contains(key)) {
					String url = uploadFile(file);
					if(StringUtils.hasLength(url)) {
						count++;
						if(StringUtils.hasLength(urls)) {
							urls += ","+url;
						}else {
							urls = url;
						}
						fileMap.put(fkey, null);
					}
				}
			}
			if(!StringUtils.hasLength(urls)) {
				continue;
			}
			if("1".equals(hasCompulsoryInsurance)) {
				String comurl = item.getCompulsoryUrl();
				if(StringUtils.hasLength(comurl)) {
					comurl += ","+urls;
				}else {
					comurl = urls;
				}
				item.setCompulsoryUrl(comurl);
				if(item.getCompulsoryUrl().split(",").length>10) {
					throw new GciBootException(item.getFrameNumber()+"上传交强险附件不能超过10个！");
				}
				update.add(item);
			}else {
				String comurl = item.getCommercialUrl();
				if(StringUtils.hasLength(comurl)) {
					comurl += ","+urls;
				}else {
					comurl = urls;
				}
				item.setCommercialUrl(comurl);
				if(item.getCommercialUrl().split(",").length>10) {
					throw new GciBootException(item.getFrameNumber()+"上传商业保险附件不能超过10个！");
				}
				update.add(item);
			}
		}
		updateBatchById(update);
		return count;
	}

	@Override
	public Result<?> listImport(List<InsuranceImportVO> list) throws IOException {

		LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		//查用户所有权限车牌
		List<TbVehicle> vehicles = projectsService.queryAllVehicleListOfUser();
		Map<String, List<Integer>> repeatMap = ValidatorUtil.findDuplicates(list, "plateNumber");

		Map<Boolean,List<InsuranceImportVO>> partitionedLists =
				list.stream().map(i->{
					i.validate();
					if(ObjectUtil.isEmpty(i.getHasCompulsoryInsurance())&&ObjectUtil.isEmpty(i.getHasCommercialInsurance())){
						i.putErrorMsg("交强险跟商业险不能同时无数据");
					}
					if(Objects.nonNull(repeatMap)&&repeatMap.containsKey(i.getPlateNumber())){
						i.putErrorMsg("存在重复的'车牌号'");
					}
					TbVehicle vehicle = vehicles.stream()
							.filter(v-> v.getPlateNumber().equals(i.getPlateNumber())).findFirst()
									.orElse(null);
					if(ObjectUtil.isEmpty(vehicle)){
						i.putErrorMsg("当前用户没有该车牌号权限或车辆不存在");
					}else{
						i.setVehicleId(vehicle.getId());
						i.setProjectId(vehicle.getProjectId());
						i.setVehicleModel(vehicle.getVehicleModel());
						i.setVehicleType(vehicle.getVehicleType());
						i.setFrameNumber(vehicle.getFrameNumber());
					}
					LambdaQueryWrapper<TbInsuranceCompanyArchives> companyArchivesWrapper = new LambdaQueryWrapper<>();
					companyArchivesWrapper.and(wrapper-> wrapper.eq(TbInsuranceCompanyArchives::getName,i.getCompulsoryCompany())
									.or().eq(TbInsuranceCompanyArchives::getShortened,i.getCompulsoryCompany())
							);
					TbInsuranceCompanyArchives companyArchives = this.tbInsuranceCompanyArchivesMapper.selectOne(companyArchivesWrapper);
					if(ObjectUtil.isEmpty(companyArchives)){
						i.putErrorMsg("系统不存在对应的保险公司");
					}else{
						i.setCompulsoryCompanyId(companyArchives.getId());
					}
					LambdaQueryWrapper<TbContract> contractLambdaQueryWrapper = new LambdaQueryWrapper<>();
					contractLambdaQueryWrapper.eq(TbContract::getContractNo,i.getContractName());
					TbContract contract = this.tbContractMapper.selectOne(contractLambdaQueryWrapper);
					if(ObjectUtil.isEmpty(contract)){
						i.putErrorMsg("系统不存在对应的保险合同");
					}else{
						i.setContractId(contract.getId());
					}

					LambdaQueryWrapper<TbInsurance> queryWrapper = new LambdaQueryWrapper<>();
					queryWrapper.eq(TbInsurance::getPlateNumber, i.getPlateNumber());
					List<TbInsurance> insurances = list(queryWrapper);
					for (TbInsurance insurance : insurances) {
						if(DateUtils.compareTo(DateUtil.parseDate(i.getCompulsoryValidTime()), insurance.getCompulsoryValidTime())<1
								&&DateUtils.compareTo(DateUtil.parseDate(i.getCompulsoryValidTime()), insurance.getCompulsoryStartTime())>-1) {
							i.putErrorMsg("有效日期不能与已有保险交叉！");
							break;
						}
						if(DateUtils.compareTo(DateUtil.parseDate(i.getCompulsoryStartTime()), insurance.getCompulsoryValidTime())<1
								&&DateUtils.compareTo(DateUtil.parseDate(i.getCompulsoryStartTime()), insurance.getCompulsoryStartTime())>-1) {
							i.putErrorMsg("起保日期不能与已有保险交叉！");
							break;
						}
					}
					i.setSysOrgCode(loginUser.getOrgCode());
					i.setCreateBy(loginUser.getUsername());
					return i;
				}).collect(Collectors.groupingBy(i->CollectionUtil.isEmpty(i.getValidationErrors())));

		List<InsuranceImportVO> failList = partitionedLists.get(false);
		List<InsuranceImportVO> successList = partitionedLists.get(true);

        if(CollectionUtil.isNotEmpty(successList)){
			List<TbInsurance> insurances = successList.stream().map(TbInsurance::buildByImportVo).collect(Collectors.toList());

			System.out.println(insurances);
			this.saveBatch(insurances);
			insuranceRemindService.updateRemind();
        }

		if (CollectionUtil.isNotEmpty(failList)) {
			JSONObject entries = new JSONObject();
			String failName = System.currentTimeMillis() + "_" +CommonConstant.INSURANCE_IMPORT_FAIL_EXCEL_NAME;
			//导出失败数据
			EasyExcel.write(failExcel + failName, InsuranceImportVO.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("导入异常数据").doWrite(failList);
			String errorMsg = "已导入"+ (list.size()-failList.size()) + "条;失败"+ failList.size() +"条;具体失败详情见失败导出信息表";
			entries.set("msg",errorMsg);
			entries.set("path",failName);
			return Result.ok(entries);
		}else{
			return Result.ok();
		}
	}

	public String uploadFile(File file) {
		String url = null;
		try {
			url = minioUtils.uploadFileValid(file, FileExtension.getCommonFileTypes());
		} catch (Exception e) {
			log.error("保险附件上传失败", e);
		}
		return url;
	}

}
