package com.pj.api.open.service;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.pj.api.open.ResultJson;
import com.pj.api.open.bo.CheckCarNumberBO;
import com.pj.api.open.bo.InRecordBO;
import com.pj.constants.UserTypeEnum;
import com.pj.current.config.SystemObject;
import com.pj.current.task.TaskService;
import com.pj.project.tb_business.BusinessMessageManager;
import com.pj.project.tb_business.TbBusiness;
import com.pj.project.tb_business.TbBusinessService;

import com.pj.project.tb_business_car.TbBusinessCar;
import com.pj.project.tb_business_car.TbBusinessCarService;
import com.pj.project.tb_business_item.TbBusinessItem;
import com.pj.project.tb_business_item.TbBusinessItemService;
import com.pj.project.tb_business_people.TbBusinessPeople;
import com.pj.project.tb_business_people.TbBusinessPeopleService;
import com.pj.project.tb_car.TbCar;
import com.pj.project.tb_car.TbCarService;
import com.pj.project.tb_car_no_color.TbCarNoColor;
import com.pj.project.tb_car_no_color.TbCarNoColorService;
import com.pj.project.tb_goods.TbGoods;
import com.pj.project.tb_goods.TbGoodsService;
import com.pj.project4sp.global.BusinessException;
import com.pj.project4sp.uploadfile.UploadConfig;
import com.pj.utils.cache.RedisUtil;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.BASE64Decoder;

import javax.annotation.Resource;
import javax.xml.crypto.Data;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class OpenService {
    @Resource
    @Lazy
    private TbBusinessService tbBusinessService;
    @Resource
    @Lazy
    private TbBusinessCarService tbBusinessCarService;
    @Resource
    @Lazy
    private TbBusinessItemService tbBusinessItemService;
    @Resource
    private TbCarService tbCarService;

    @Resource
    TaskService taskService;
    @Resource
    TbCarNoColorService tbCarNoColorService;

    @Resource
    private TbGoodsService tbGoodsService;


    private final List<String> CAR_LIST = StrUtil.splitTrim("浙,粤,京,津,冀,晋,蒙,辽,黑,沪,吉,苏,皖,赣,鲁,豫,鄂,湘,桂,琼,渝,川,贵,云,藏, 陕, 甘, 青, 宁", ",");


    public ResultJson checkCarNumber(CheckCarNumberBO checkCarNumberBO) {
        String carNo = checkCarNumberBO.getCarNumber();
        int inOrOut = checkCarNumberBO.getInOrOut();
        String image = checkCarNumberBO.getImageData();
        if (inOrOut == 1) {
            handlerIn(carNo, checkCarNumberBO.getChannelName(), image);
            return ResultJson.success();
        }
        return handlerOut(carNo, checkCarNumberBO.getChannelName(), image);

    }

    private void handlerIn(String carNo, String channel, String image) {
        carNo = carNo.toUpperCase();
        if (StrUtil.isNotEmpty(image)) {
            StaticLog.error("缓存入场图片:{}", carNo);
            IMAGE_CACHE.put(carNo, image);
        }
        TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo);
        Date now = new Date();
        TbCar tbCar = tbCarService.findByCardNo(carNo);
        if (tbBusinessCar == null
                || (tbBusinessCar.getRealInTime() != null && tbBusinessCar.getRealOutTime() != null)
                || (tbBusinessCar.getRealInTime() != null && tbBusinessCar.getRealOutTime() == null)
                || tbBusinessCar.getPay() == 1) {
            tbBusinessCar = new TbBusinessCar();
            tbBusinessCar.setCarNo(carNo).setPay(0).setCarSize(0D).setIsLock(0).setCarCompany(tbCar != null ? tbCar.getCustomerName() : "临时")
                    .setInChannel(channel).setRealInTime(now).setBasePartMoney(new BigDecimal("0")).setTimeUpdate(now)
                    .setNo(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")) + RandomUtil.randomNumbers(4));
            tbBusinessCarService.save(tbBusinessCar);
            CoverBase64ToUrl(image, tbBusinessCar.getId(), carNo, 1);
            return;
        }
        tbBusinessCar.setRealInTime(now).setInChannel(channel).setTimeUpdate(now)
                .setCarCompany(tbCar != null ? tbCar.getCustomerName() : "临时");
        tbBusinessCarService.saveOrUpdate(tbBusinessCar);
        CoverBase64ToUrl(image, tbBusinessCar.getId(), carNo, 1);
        if (!CAR_LIST.contains(carNo)) {
            TbBusiness tbBusiness = tbBusinessService.getById(tbBusinessCar.getBusinessId());
            if (tbBusiness != null) {
                tbBusiness.setRealInTime(now).setInChannel(channel);
                tbBusinessService.updateById(tbBusiness);
            }
        }

    }

    private void CoverBase64ToUrl(String base64image, String carId, String carNo, int inOrOut) {
        String cacheBase64 = IMAGE_CACHE.get(carNo);
        if (StrUtil.isEmpty(base64image)) {
            base64image = cacheBase64;
        }
        if (StrUtil.isEmpty(base64image)) {
            log.error("无出场图片:{}", carNo);
            return;
        }
        taskService.addTask(new CoverBase64ToImageTask("=======" + carId + "", 2000, carId, base64image, inOrOut));
        IMAGE_CACHE.remove(carNo);
    }

    final TimedCache<String, String> IMAGE_CACHE = CacheUtil.newTimedCache(30 * 60 * 1000);

    private ResultJson handlerOut(String carNo, String channel, String image) {
        carNo = carNo.toUpperCase();
        TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo);
        if (tbBusinessCar == null || tbBusinessCar.getRealInTime() == null || tbBusinessCar.getRealOutTime() != null) {
            log.error("请求返回【未查询到入场记录】:{}", carNo);
            return ResultJson.error("未查询到入场记录");
        }
        if (StrUtil.isNotEmpty(image)) {
            StaticLog.error("缓存离场图片,{}", carNo);
            IMAGE_CACHE.put(carNo, image);
        }
        Date now = new Date();
        //判断是否蓝色车牌===免停车费
        if (StrUtil.isNotEmpty(tbBusinessCar.getColor())) {
            List<TbCarNoColor> freeList = tbCarNoColorService.getFreeColor();
            List<String> colorList = freeList.stream().map(f -> f.getCarNoColor().substring(0, 1)).collect(Collectors.toList());
            String color = tbBusinessCar.getColor().substring(0, 1);
            if (colorList.contains(color)) {
                freeOut(tbBusinessCar, now, channel, image);
                return ResultJson.success();
            }
        }
        //是否行政车辆=====
        if (checkFree(carNo, 2, now)) {
            freeOut(tbBusinessCar, now, channel, image);
            return ResultJson.success();
        }
        if (tbBusinessCar.getIsLock() == 1) {
            RedisUtil.setByMINUTES(channel, carNo, 2);
            log.error("请求返回：车辆已锁定:{}", carNo);
            return ResultJson.error("车辆已锁定");
        }
        String businessCarId = tbBusinessCar.getId();
        String carNoPrefix = StrUtil.sub(carNo, 0, 1);
        List<TbBusiness> businessList = tbBusinessService.findOtherBusinessByCarId(businessCarId);
        if (businessList.isEmpty()) {//无业务车辆===>计算停车费
            //如果已经支付过，则从支付时间算起，重新计算停车费
            double dif = caulatePrice(tbBusinessCar, now);
            if (dif > 0) {
                RedisUtil.setByMINUTES(channel, carNo, 1);
                log.error("请求返回：请缴停车费:{}，{}元", carNo, dif);
                return ResultJson.error("请缴停车费" + dif + "元");
            } else {
                freeOut(tbBusinessCar, now, channel, image);
                return ResultJson.success();
            }
        } else {
            //有业务的车
            //1、分越南车和中国车
            //中国车是否收费
            if (CAR_LIST.contains(carNoPrefix)) {
                boolean chinaCarPay = businessList.stream().anyMatch(tbBusiness -> {
                    TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
                    return tbGoods.getChinaCarPay() == 1;
                });
                if (chinaCarPay) {
                    double dif = caulatePrice(tbBusinessCar, now);
                    if (dif > 0) {
                        RedisUtil.setByMINUTES(channel, carNo, 1);
                        log.error("请求返回：请缴停车费:{}，{}元", carNo, dif);
                        return ResultJson.error("请缴停车费" + dif + "元");
                    }
                }
            } else {//越南车
                boolean vietnamCarPay = businessList.stream().anyMatch(tbBusiness -> {
                    TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
                    return tbGoods.getVietnamCarPay() == 1;
                });
                if (vietnamCarPay) {
                    double dif = caulatePrice(tbBusinessCar, now);
                    if (dif > 0) {
                        RedisUtil.setByMINUTES(channel, carNo, 1);
                        log.error("请求返回：请缴停车费:{}，{}元", carNo, dif);
                        return ResultJson.error("请缴停车费" + dif + "元");
                    }
                }
            }
        }
        //============业务费计算是否交完
        for (TbBusiness tbBusiness : businessList) {
            TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
            int vietnamLeave = tbGoods.getVietnamCarLeave();
            int chinaCarLeave = tbGoods.getChinaCarLeave();
            boolean pay = tbBusiness.getPayMoney().doubleValue() >= tbBusiness.getItemPrice().doubleValue();
            //需要交业务费
            if (!CAR_LIST.contains(carNoPrefix)) {//越南车
                if (TbGoods.LeaveEnum.PART_MONEY.getCode() != vietnamLeave
                        && !pay) {
                    RedisUtil.setByMINUTES(channel, carNo, 1);
                    log.error("请求返回：请缴纳业务费用:{}", carNo);
                    return ResultJson.error("请缴纳业务费用");
                }
            } else {
                if (TbGoods.LeaveEnum.PART_MONEY.getCode() != chinaCarLeave
                        && !pay) {
                    RedisUtil.setByMINUTES(channel, carNo, 1);
                    log.error("请求返回：请缴纳业务费用:{}", carNo);
                    return ResultJson.error("请缴纳业务费用");
                }
            }
        }
        freeOut(tbBusinessCar, now, channel, image);
        return ResultJson.success();
    }


    private double caulatePrice(TbBusinessCar tbBusinessCar, Date now) {
        Date inTime = tbBusinessCar.getRealInTime();
        if (tbBusinessCar.getPay() == 1 && tbBusinessCar.getRealOutTime() == null && tbBusinessCar.getPayTime() != null) {
            inTime = tbBusinessCar.getPayTime();
        }
        BigDecimal price = tbBusinessService.calculationPartMoney(inTime, now);
        return price.doubleValue();
    }

    private void freeOut(TbBusinessCar tbBusinessCar, Date now, String outChannel, String base64Image) {
        tbBusinessCar.setRealOutTime(now).setTimeUpdate(now).setOutChannel(outChannel);
        tbBusinessCarService.updateById(tbBusinessCar);
        String carNo = tbBusinessCar.getCarNo();
        CoverBase64ToUrl(base64Image, tbBusinessCar.getId(), carNo, 2);
        RedisUtil.del(outChannel);
        log.error("请求返回【放行】:{}", carNo);
    }

    private boolean checkFree(String carNo, int inOrOut, Date now) {
        TbCar tbCar = tbCarService.findByCardNo(carNo);
        if (tbCar != null) {
            if (inOrOut == 1) {
                tbCar.setLastInTime(now);
            } else {
                tbCar.setLastOutTime(now);
            }
            tbCarService.updateById(tbCar);
        }
        return tbCar != null && !TbCar.CarTypeEnum.BUSINESS_CAR.getType().equals(tbCar.getCarType());
    }


    @Async
    public void handlerInRecord(InRecordBO inRecordBO) {
        List<TbCarNoColor> carNoColorList = tbCarNoColorService.getFreeColor();
        String freeColors = carNoColorList.stream().map(TbCarNoColor::getCarNoColor).collect(Collectors.joining(","));
        String carNo = inRecordBO.getCarNumber().trim().toUpperCase();
        // 入场==>取车牌颜色
        List<TbBusinessCar> cars = tbBusinessCarService.findByCarNo(carNo);
        cars.stream().filter(obj -> StrUtil.isEmpty(obj.getColor()))
                .forEach(tbBusinessCar -> {
                    String color = inRecordBO.getCarColor();
                    String prefixColor = StrUtil.sub(color, 0, 1);
                    if (StrUtil.contains(freeColors, prefixColor)) {
                        tbBusinessCar.setPayType(TbBusinessCar.PayTypeEnum.FEE_TYPE.getType());
                    }
                    TbCar tbCar = tbCarService.findByCardNo(tbBusinessCar.getCarNo());
                    if (tbCar != null && !TbCar.CarTypeEnum.BUSINESS_CAR.getType().equals(tbCar.getCarType())) {
                        tbBusinessCar.setPayType(TbBusinessCar.PayTypeEnum.FEE_TYPE.getType());
                    }
                    tbBusinessCar.setColor(color);
                    tbBusinessCarService.updateById(tbBusinessCar);
                });
    }
}
