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

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gci.boot.modules.gis.entity.TbGisRunningbus;
import com.gci.boot.modules.gis.service.ITbGisRunningbusService;
import com.gci.boot.modules.vehicles.service.ITbAnnualInspectionRemindService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.common.util.BeanUtilsCopy;
import com.gci.boot.common.util.DateUtils;
import com.gci.boot.common.util.Lock;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.basedata.entity.TbVehicle;
import com.gci.boot.modules.basedata.service.ITbVehicleService;
import com.gci.boot.modules.projects.entity.TbContract;
import com.gci.boot.modules.projects.entity.TbVehicleCheck;
import com.gci.boot.modules.projects.entity.TbVehicleCheckDetail;
import com.gci.boot.modules.projects.mapper.TbVehicleCheckMapper;
import com.gci.boot.modules.projects.service.IProjectVehicleBindLogService;
import com.gci.boot.modules.projects.service.ITbContractService;
import com.gci.boot.modules.projects.service.ITbVehicleCheckDetailService;
import com.gci.boot.modules.projects.service.ITbVehicleCheckProjectService;
import com.gci.boot.modules.projects.service.ITbVehicleCheckService;
import com.gci.boot.modules.vehicles.entity.TbAnnualInspectionInfo;
import com.gci.boot.modules.vehicles.mapper.TbAccidentProgressMapper;
import com.gci.boot.modules.vehicles.mapper.TbViolationRecordMapper;
import com.gci.boot.modules.vehicles.service.ITbAnnualInspectionInfoService;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 车辆验收 服务实现类
 * </p>
 *
 * @author xushuhan
 * @since 2023-09-11
 */
@Slf4j
@Service
public class TbVehicleCheckServiceImpl extends ServiceImpl<TbVehicleCheckMapper, TbVehicleCheck> implements ITbVehicleCheckService {

	@Autowired
	private ITbVehicleCheckProjectService tbVehicleCheckProjectService;
	@Autowired
	private ITbVehicleCheckDetailService tbVehicleCheckDetailService;
	@Autowired
	private ITbContractService tbContractService;
	@Autowired
	private TbAccidentProgressMapper accidentProgressMapper;
	@Autowired
	private TbViolationRecordMapper violationRecordMapper;
	@Autowired
	private ITbVehicleService vehicleService;

    @Autowired
    private IProjectVehicleBindLogService projectVehicleBindLogService;

    @Autowired
    private ITbAnnualInspectionInfoService annualInspectionInfoService;

    @Autowired
	private ITbAnnualInspectionRemindService annualInspectionRemindService;

    @Autowired
    private Lock lock;
	@Autowired
	private ITbGisRunningbusService gisRunningbusService;
    
    DecimalFormat df2 = new DecimalFormat("#.00");
    
	@Transactional
	@Override
	public String saveItem(TbVehicleCheck item) {
		tbVehicleCheckDetailService.checkVehicle(item);
		if("3".equals(item.getCheckType())) {
			TbVehicleCheck parent = getById(item.getParentId());
			if(!StringUtils.hasLength(item.getParentId())||parent==null) {
				throw new GciBootException("租赁交车不能为空!");
			}
			item.setProjectId(parent.getProjectId());
			item.setContractId(parent.getContractId());
			item.setVehicleType(parent.getVehicleType());
			item.setTemplateId(parent.getTemplateId());
			item.setRegistrationTime(parent.getRegistrationTime());
		}
		if("2".equals(item.getCheckType())&&"1".equals(item.getStatus())) {
			item.setReceiveStatus("0.5");
		}
		saveOrUpdate(item);
		if("1".equals(item.getCheckType())&&"1".equals(item.getStatus())&&item.getVehicleList()!=null&&item.getVehicleList().size()!=0) {
			createVehicle(item);
			createAnnualInspectionInfo(item);
		}
		if(!"3".equals(item.getCheckType())) {
			tbVehicleCheckDetailService.saveItem(item);
			tbVehicleCheckProjectService.saveItem(item);
			tbContractService.updateStatus(item.getContractId());
		}else {
			String error = updateStatus(item.getParentId());
			return error;
		}
		return "";
	}

	//获取租赁收车
	@Override
	public void getChildren(TbVehicleCheck parent) {
		if("2".equals(parent.getCheckType())) {
			LambdaQueryWrapper<TbVehicleCheck> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.eq(TbVehicleCheck::getParentId,parent.getId());
			List<TbVehicleCheck> list = list(queryWrapper);
			if(list.size()>0) {
				parent.setChildren(list.get(0));
			}
		}
	}

	//获取未处理违章数、未处理事故数
	@Override
	public void initItem(List<TbVehicleCheck> list) {
		if(list.size()<1) {
			return;
		}
		List<TbVehicleCheck> accident = accidentProgressMapper.getCheckAccidentInfoCount();
		Map<String,TbVehicleCheck> accidentMap = new HashMap<>();
		for (TbVehicleCheck vo : accident) {
			accidentMap.put(vo.getId()+vo.getProjectId(), vo);
		}

		List<TbVehicleCheck> violation = violationRecordMapper.getCheckViolationCount();
		Map<String,TbVehicleCheck> violationMap = new HashMap<>();
		for (TbVehicleCheck vo : violation) {
			violationMap.put(vo.getId()+vo.getProjectId(), vo);
		}

		for(TbVehicleCheck item:list) {
			String key = item.getId()+item.getProjectId();
			if(accidentMap.containsKey(key)) {
				item.setAccidentInfoCount(accidentMap.get(key).getAccidentInfoCount());
			}
			if(violationMap.containsKey(key)) {
				item.setViolationCount(violationMap.get(key).getViolationCount());
			}
		}
	}

	//租赁交车状态更新
	public String updateStatus(String id) {
		LambdaQueryWrapper<TbVehicleCheck> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TbVehicleCheck::getReceiveStatus, "0.5");
		queryWrapper.eq(TbVehicleCheck::getStatus, "1");
		queryWrapper.eq(TbVehicleCheck::getCheckType, "2");
		queryWrapper.eq(StringUtils.hasLength(id),TbVehicleCheck::getId, id);
		List<TbVehicleCheck> list = list(queryWrapper);
		initItem(list);
		String error = "";
		for (TbVehicleCheck item : list) {
			getChildren(item);
			if(item.getChildren()==null||"0".equals(item.getChildren().getStatus())) {
				continue;
			}
			if(item.getAccidentInfoCount()==0&&item.getViolationCount()==0) {
				item.setReceiveStatus("1");
				updateById(item);
			}else {
				error = "当前车辆有违章或事故未处理，请及时处理！";
			}
		}
		return error;
	}


    @Scheduled(cron = "0 */10 * * * ?")
	public void statusTask() {
    	log.info("---------租赁交车状态更新----------");
		String key = CommonConstant.CHECK_STATUS_TASK_LOCK;
        String value = lock.getUniqueNum();
        int n  = 0 ;
        try {
            n = lock.getLock(key, value);
            if(n > 0){
            	updateStatus(null);
            }
        }catch (Exception ex){
            log.error("租赁交车状态更新出错, {}", ex);
        }finally {
            //释放锁
            if(n > 0){
                lock.delLock(key, value);
            }
        }
	}

    //生成车辆档案
    public List<TbVehicle> createVehicle(TbVehicleCheck item) {
    	List<TbVehicle> vlist = vehicleService.list();
    	Set<String> frameNumberSet = vlist.stream().map(t->t.getFrameNumber()).collect(Collectors.toSet());
    	Set<String> plateNumberSet = vlist.stream().map(t->t.getPlateNumber()).collect(Collectors.toSet());
    	List<TbVehicle> ves = new ArrayList<>();
    	TbContract contract = tbContractService.getById(item.getContractId());
    	String name = "";
    	if(contract!=null) {
    		name = contract.getSigningId();
    	}
    	Map<String, Double> pmap = tbContractService.getCarPrice(item.getContractId());
    	//TODO 验证车牌，车架等
    	for (TbVehicleCheckDetail vd : item.getVehicleList()) {
    		if(frameNumberSet.contains(vd.getFrameNumber())) {
    			continue;
    		}
    		if(plateNumberSet.contains(vd.getPlateNumber())) {
    			continue;
    		}
    		TbVehicle tbVehicle = new TbVehicle();
    		BeanUtilsCopy.copyBeanProp(tbVehicle, vd);
    		tbVehicle.setProjectId(item.getProjectId());
    		if(StrUtil.isBlank(tbVehicle.getProjectId())){
                tbVehicle.setProjectId(CommonConstant.INNER_PROJECT);
            }else {
                projectVehicleBindLogService.addLog(tbVehicle.getProjectId(), null,tbVehicle.getPlateNumber(),1,1,item.getCreateBy());
            }
    		tbVehicle.setVinCode(tbVehicle.getFrameNumber());
    		tbVehicle.setSourceType("2");
    		tbVehicle.setDealer(name);
    		tbVehicle.setDeliveryTime(new Date());
    		if(pmap.containsKey(tbVehicle.getVehicleModel())) {
    			tbVehicle.setPrice(pmap.get(tbVehicle.getVehicleModel()));
			}
    		vehicleService.save(tbVehicle);

    		vd.setVehicleId(tbVehicle.getId());
    		ves.add(tbVehicle);
			//更新runningBus项目id
			CompletableFuture.runAsync(() -> {
				gisRunningbusService.update(new LambdaUpdateWrapper<TbGisRunningbus>().eq(TbGisRunningbus::getPlateNumber,tbVehicle.getPlateNumber())
						.set(TbGisRunningbus::getProjectId,tbVehicle.getProjectId()));
			});
		}
    	return ves;
    }

    //生成年检信息
    public void createAnnualInspectionInfo(TbVehicleCheck item) {
    	if(item.getRegistrationTime()==null) {
    		return;
    	}
    	List<TbAnnualInspectionInfo> vlist = annualInspectionInfoService.list();
    	Set<String> plateNumberSet = vlist.stream().map(t->t.getPlateNumber()).collect(Collectors.toSet());
    	List<TbAnnualInspectionInfo> alist = new ArrayList<>();
    	Date today = item.getRegistrationTime();
    	Date nextYear = DateUtils.addYear(today, 1);
    	for (TbVehicleCheckDetail vd : item.getVehicleList()) {
    		if(plateNumberSet.contains(vd.getPlateNumber())) {
    			continue;
    		}
    		TbAnnualInspectionInfo info = new TbAnnualInspectionInfo();
    		BeanUtilsCopy.copyBeanProp(info, vd);
    		if(StrUtil.isBlank(info.getProjectId())){
    			info.setProjectId(CommonConstant.INNER_PROJECT);
            }
    		info.setHandlingDate(today);
    		info.setValidityPeriod(nextYear);
    		info.setProcessedPerson(item.getCreateBy());
    		if(!StringUtils.hasLength(info.getProcessedPerson())){
    			info.setProcessedPerson("");
    		}
    		info.setMiscellaneousFee(BigDecimal.ZERO);
    		info.setServiceFee(BigDecimal.ZERO);
    		info.setTestingFee(BigDecimal.ZERO);
    		info.setTotalFee(BigDecimal.ZERO);
    		info.setSourceType("2");
    		alist.add(info);
    	}
    	annualInspectionInfoService.saveBatch(alist);
    	annualInspectionRemindService.init();
    }


}
