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

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.poi.ss.usermodel.Workbook;
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.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.annotation.importHandler.ExcelTypeHandler;
import com.gci.boot.annotation.importHandler.MyExcelVerifyHandler;
import com.gci.boot.common.validated.ImportValidated;
import com.gci.boot.common.vo.Result;
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.Projects;
import com.gci.boot.modules.projects.mapper.ProjectsMapper;
import com.gci.boot.modules.system.vo.LoginUser;
import com.gci.boot.modules.vehicles.entity.TbAccidentInfo;
import com.gci.boot.modules.vehicles.entity.TbAnnualInspectionInfo;
import com.gci.boot.modules.vehicles.entity.TbAnnualInspectionRemind;
import com.gci.boot.modules.vehicles.entity.TbViolationRecord;
import com.gci.boot.modules.vehicles.mapper.TbAccidentInfoMapper;
import com.gci.boot.modules.vehicles.mapper.TbAnnualInspectionInfoMapper;
import com.gci.boot.modules.vehicles.query.AnnualInspectionInfoQuery;
import com.gci.boot.modules.vehicles.service.ITbAnnualInspectionInfoService;
import com.gci.boot.modules.vehicles.service.ITbAnnualInspectionRemindService;
import com.gci.boot.modules.vehicles.service.ITbViolationRecordService;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;

/**
 * <p>
 * 年检信息表 服务实现类
 * </p>
 *
 * @author 2464
 * @since 2023-09-20
 */
@Service
public class TbAnnualInspectionInfoServiceImpl extends ServiceImpl<TbAnnualInspectionInfoMapper, TbAnnualInspectionInfo>
    implements ITbAnnualInspectionInfoService {

    @Autowired
    private TbAnnualInspectionInfoMapper annualInspectionInfoMapper;
    @Autowired
    private ITbVehicleService vehicleService;
    @Resource
    private ITbViolationRecordService violationRecordService;
    @Resource
    private TbAccidentInfoMapper accidentInfoMapper;
    @Autowired
    private ITbAnnualInspectionRemindService annualInspectionRemindService;
    @Autowired
    private ProjectsMapper projectsMapper;
    @Autowired
    private MyExcelVerifyHandler<TbAnnualInspectionInfo> myExcelVerifyHandler;

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

    @Override
    public IPage<TbAnnualInspectionInfo> pageBuild(Page<TbAnnualInspectionInfo> page, AnnualInspectionInfoQuery query) {
        checkTime(query);
        return annualInspectionInfoMapper.pageBuild(page, query);
    }

    private void checkTime(AnnualInspectionInfoQuery query) {
        List<Date> time = query.getTime();
        if (ObjectUtil.isNotEmpty(time)) {
            if (time.size() != 2) {
                throw new GciBootException("年审有效期必须包括起止时间！");
            }
            if (DateUtil.between(time.get(0), time.get(1), DateUnit.MS, false) < 0) {
                throw new GciBootException("开始时间不能大于结束时间！");
            }
        }
    }

    @Override
    public IPage<TbAnnualInspectionInfo> remindList(Page<TbAnnualInspectionInfo> page,
        AnnualInspectionInfoQuery query) {
        checkTime(query);
        IPage<TbAnnualInspectionInfo> tbAnnualInspectionInfoIPage = annualInspectionInfoMapper.remindList(page, query);
        for (TbAnnualInspectionInfo record : tbAnnualInspectionInfoIPage.getRecords()) {
            Integer days = record.getDays();
            if (days > 0) {
                record.setDaysToOverdue(days);
            } else {
                record.setOverdueDays(-days);
            }
            int violationCount = violationRecordService.count(new LambdaQueryWrapper<TbViolationRecord>()
                .eq(TbViolationRecord::getPlateNumber, record.getPlateNumber())
                .eq(TbViolationRecord::getHandleResult, 0));
            record.setViolationCount(violationCount);
            Integer integer = accidentInfoMapper.countAccidentNotClose(
                new QueryWrapper<TbAccidentInfo>().eq("tai.plate_number", record.getPlateNumber())
                    .and(i -> i.eq("tap.case_closed", CommonConstant.NO).or().isNull("tap.case_closed")));
            record.setAccidentCount(integer);
        }
        return tbAnnualInspectionInfoIPage;
    }

    @Override
    public void init() {
        List<TbVehicle> list = vehicleService.list();

        ArrayList<TbAnnualInspectionInfo> annualInspectionInfoArrayList = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();
        for (TbVehicle vehicle : list) {
            TbAnnualInspectionInfo annualInspectionInfo = new TbAnnualInspectionInfo();
            annualInspectionInfo.setPlateNumber(vehicle.getPlateNumber());
            if (StrUtil.isBlank(vehicle.getProjectId())) {
                strings.add(vehicle.getPlateNumber());
                continue;
            }
            annualInspectionInfo.setProjectId(vehicle.getProjectId());
            annualInspectionInfo.setProcessedPerson("系统");
            annualInspectionInfo.setHandlingDate(vehicle.getDeliveryTime());
            annualInspectionInfo
                .setValidityPeriod(DateUtil.offset(vehicle.getDeliveryTime(), DateField.DAY_OF_YEAR, 365));
            annualInspectionInfo.setServiceFee(BigDecimal.ZERO);
            annualInspectionInfo.setMiscellaneousFee(BigDecimal.ZERO);
            annualInspectionInfo.setTestingFee(BigDecimal.ZERO);
            annualInspectionInfo.setTotalFee(BigDecimal.ZERO);
            annualInspectionInfoArrayList.add(annualInspectionInfo);
        }
        if (ObjectUtil.isNotEmpty(strings)) {
            log.warn("无项目车辆" + strings.toString());
        }
        saveBatch(annualInspectionInfoArrayList);
    }

    @Override
    public TbAnnualInspectionInfo getLastYear(String plateNumber) {
        TbAnnualInspectionInfo one = getOne(
            new LambdaQueryWrapper<TbAnnualInspectionInfo>().eq(TbAnnualInspectionInfo::getPlateNumber, plateNumber)
                .orderByDesc(TbAnnualInspectionInfo::getValidityPeriod).last("limit 1"));
        if (BeanUtil.isEmpty(one)) {
            one = new TbAnnualInspectionInfo();
            one.setServiceFee(BigDecimal.ZERO);
            one.setTestingFee(BigDecimal.ZERO);
            one.setTotalFee(BigDecimal.ZERO);
            one.setMiscellaneousFee(BigDecimal.ZERO);
        }
        return one;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveItem(TbAnnualInspectionInfo tbAnnualInspectionInfo) {
        save(tbAnnualInspectionInfo);
        TbAnnualInspectionRemind annualInspectionRemind =
            annualInspectionRemindService.buildRemind(tbAnnualInspectionInfo);
        annualInspectionRemindService.save(annualInspectionRemind);
        annualInspectionRemindService.recalculate(tbAnnualInspectionInfo.getPlateNumber());
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void updateItem(TbAnnualInspectionInfo tbAnnualInspectionInfo) {
        updateById(tbAnnualInspectionInfo);
        TbAnnualInspectionRemind accidentInsuranceRemind =
            annualInspectionRemindService.findRemind(tbAnnualInspectionInfo);
        if (accidentInsuranceRemind != null) {
            annualInspectionRemindService.updateById(accidentInsuranceRemind);
            annualInspectionRemindService.recalculate(tbAnnualInspectionInfo.getPlateNumber());
        } else {
            TbAnnualInspectionRemind annualInspectionRemind =
                annualInspectionRemindService.buildRemind(tbAnnualInspectionInfo);
            annualInspectionRemindService.save(annualInspectionRemind);
            annualInspectionRemindService.recalculate(tbAnnualInspectionInfo.getPlateNumber());
        }
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void removeItem(String id) {
        TbAnnualInspectionInfo byId = getById(id);
        if (BeanUtil.isEmpty(byId)) {
            throw new GciBootException("id错误！");
        }
        removeById(id);
        annualInspectionRemindService
            .remove(new LambdaQueryWrapper<TbAnnualInspectionRemind>().eq(TbAnnualInspectionRemind::getInfoId, id));
        annualInspectionRemindService.recalculate(byId.getPlateNumber());
    }

    @Override
    public Result<?> listImport(MultipartFile file) throws IOException {
        LoginUser loginUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
        String realname = loginUser.getRealname();

        String name = "车辆年检导出错误"+System.currentTimeMillis()+".xlsx";

        JSONObject entries = new JSONObject();

        // 有权限项目
        List<Projects> list = projectsMapper.getAllProjects();
        // 有权限的车辆
        List<TbVehicle> tbVehicles = new ArrayList<>();
        if (!list.isEmpty()) {
            tbVehicles = vehicleService.list(new LambdaQueryWrapper<TbVehicle>().in(TbVehicle::getProjectId,
                list.stream().map(Projects::getId).collect(Collectors.toList())));
        }
        Map<String, String> plateNumberProjectId =
            tbVehicles.stream().collect(Collectors.toMap(TbVehicle::getPlateNumber, TbVehicle::getProjectId));

        List<TbAnnualInspectionInfo> annualInspectionInfoList = this.list();

        ImportParams importParams = new ImportParams();
        importParams.setNeedVerify(true);
        importParams.setVerifyGroup(new Class[] {ImportValidated.class});
        importParams.setVerifyHandler(myExcelVerifyHandler);

        ArrayList<ExcelTypeHandler> excelTypeHandlers = new ArrayList<>();

        List<String> v = new ArrayList<>();
        v.add("plateNumber");
        v.add("validityPeriod");
        ExcelTypeHandler excelTypeHandler1 = new ExcelTypeHandler(v, true, annualInspectionInfoList, "车牌号，有效期重复！");
        excelTypeHandlers.add(excelTypeHandler1);

        List<String> p = new ArrayList<>();
        p.add("plateNumber");
        List<String> collect = tbVehicles.stream().map(TbVehicle::getPlateNumber).collect(Collectors.toList());
        ExcelTypeHandler excelTypeHandler2 = new ExcelTypeHandler(p, collect, "无对应车辆权限或车辆不存在系统内!");
        excelTypeHandlers.add(excelTypeHandler2);
        myExcelVerifyHandler.setList(excelTypeHandlers);

        InputStream inputStream = file.getInputStream();
        try {
            ExcelImportResult<TbAnnualInspectionInfo> result =
                ExcelImportUtil.importExcelMore(inputStream, TbAnnualInspectionInfo.class, importParams);

            List<TbAnnualInspectionInfo> failList = result.getFailList();
            List<TbAnnualInspectionInfo> successList = result.getList();
            // 成功的数据处理
            if (!successList.isEmpty()) {
                for (TbAnnualInspectionInfo annualInspectionInfo : successList) {
                    if (StrUtil.isBlank(annualInspectionInfo.getProcessedPerson())) {
                        annualInspectionInfo.setProcessedPerson(realname);
                    }
                    BigDecimal total = NumberUtil.add(annualInspectionInfo.getServiceFee(),
                        annualInspectionInfo.getMiscellaneousFee(), annualInspectionInfo.getTestingFee());
                    annualInspectionInfo.setTotalFee(total);
                    annualInspectionInfo.setProjectId(plateNumberProjectId.get(annualInspectionInfo.getPlateNumber()));
                }
                saveBatch(successList);
                annualInspectionRemindService.init();
            }

            if (!failList.isEmpty()) {
                Workbook failWorkbook = result.getFailWorkbook();
                String fullPath = failExcel + name;
                FileOutputStream fileOutputStream = new FileOutputStream(fullPath);
                failWorkbook.write(fileOutputStream);
                fileOutputStream.close();
                String errorMsg = StrUtil.format("已导入{}条;失败{}条;具体失败详情见失败导出信息表；", successList.size(), failList.size());
                entries.set("msg", errorMsg);
                entries.set("path", name);
                return Result.ok(entries);
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new GciBootException("导入失败请联系管理员！");
        } finally {
            inputStream.close();
            ThreadLocal<List<TbAnnualInspectionInfo>> threadLocal = myExcelVerifyHandler.getThreadLocal();
            if (threadLocal != null) {
                threadLocal.remove();
            }
        }
        return Result.ok();
    }

    private HashSet<String> getValues(String key) {
        return new HashSet<String>();
    }
}
