package com.hotwj.platform.resourceManagement.vehicleAnnualReview.controller;

import cn.idev.excel.annotation.ExcelIgnore;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.hotwj.platform.config.vehicleInspectionConfig.domain.bo.HotVehicleInspectionConfigBo;
import com.hotwj.platform.config.vehicleInspectionConfig.domain.vo.HotVehicleInspectionConfigVo;
import com.hotwj.platform.config.vehicleInspectionConfig.service.IHotVehicleInspectionConfigService;
import com.hotwj.platform.resourceManagement.vehicleAnnualReview.domain.bo.HotVehicleAnnualReviewBo;
import com.hotwj.platform.resourceManagement.vehicleAnnualReview.domain.vo.HotVehicleAnnualReviewVo;
import com.hotwj.platform.resourceManagement.vehicleAnnualReview.service.IHotVehicleAnnualReviewService;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.bo.HotVehicleStatusBo;
import com.hotwj.platform.resourceManagement.vehicleManagement.domain.vo.HotVehicleVo;
import com.hotwj.platform.resourceManagement.vehicleManagement.service.IHotVehicleService;
import com.hotwj.platform.resourceManagement.vehicleManagement.utils.VehicleUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * 车辆年审明细
 *
 * @author shihongwei
 * @date 2025-12-15
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/resourceManagement/vehicleAnnualReview")
@Tag(name = "车辆年审明细", description = "车辆年审明细管理")
public class HotVehicleAnnualReviewController extends BaseController {

    private final IHotVehicleAnnualReviewService hotVehicleAnnualReviewService;
    private final IHotVehicleService hotVehicleService;
    private final IHotVehicleInspectionConfigService hotVehicleInspectionConfigService;

    private static LocalDate toLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

	
    /**
     * 查询车辆年审明细列表
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:list")
    @GetMapping("/list")
    @Operation(summary = "查询车辆年审明细列表")
    public TableDataInfo<HotVehicleAnnualReviewVo> list(HotVehicleAnnualReviewBo bo, PageQuery pageQuery) {
        return hotVehicleAnnualReviewService.queryPageList(bo, pageQuery);
    }

    /**
     * 导出车辆年审状态列表
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:export")
    @Log(title = "车辆年审状态", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @Operation(summary = "导出车辆年审状态列表")
    public void export(HotVehicleStatusBo bo, HttpServletResponse response) {
        Long companyId = bo != null ? bo.getCompanyId() : null;
        if (companyId == null) {
            ExcelUtil.exportExcel(new ArrayList<>(), "车辆年审", VehicleAnnualInspectionStatusVo.class, response);
            return;
        }

        HotVehicleInspectionConfigBo configBo = new HotVehicleInspectionConfigBo();
        configBo.setCompanyId(companyId);
        configBo.setIsEnabled(1L);
        configBo.setIsDeleted(0L);
        List<HotVehicleInspectionConfigVo> configs = hotVehicleInspectionConfigService.queryList(configBo);
        configs = configs == null ? new ArrayList<>() : configs.stream()
                .filter(c -> c != null && (c.getIsEnabled() == null || c.getIsEnabled() == 1L))
                .sorted(Comparator.comparing(c -> c.getIntervalYears() == null ? Long.MAX_VALUE : c.getIntervalYears()))
                .toList();

        List<VehicleUtils.AnnualInspectionRule> rules = new ArrayList<>();
        for (HotVehicleInspectionConfigVo c : configs) {
            if (c.getIntervalYears() == null || c.getInspectionTimes() == null) {
                continue;
            }
            rules.add(new VehicleUtils.AnnualInspectionRule(c.getIntervalYears().intValue(), c.getInspectionTimes().intValue()));
        }

        if (bo == null) {
            bo = new HotVehicleStatusBo();
        }
        bo.setCompanyId(companyId);
        PageQuery pageQuery = new PageQuery(Integer.MAX_VALUE, PageQuery.DEFAULT_PAGE_NUM);
        TableDataInfo<HotVehicleVo> vehiclePage = hotVehicleService.queryPageListByStatus(bo, pageQuery);
        List<HotVehicleVo> vehicles = vehiclePage.getRows();
        if (vehicles == null || vehicles.isEmpty()) {
            ExcelUtil.exportExcel(new ArrayList<>(), "车辆年审", VehicleAnnualInspectionStatusVo.class, response);
            return;
        }

        List<VehicleAnnualInspectionStatusVo> rows = buildAnnualInspectionRows(vehicles, rules);
        ExcelUtil.exportExcel(rows, "车辆年审", VehicleAnnualInspectionStatusVo.class, response);
    }

    /**
     * 获取车辆年审明细详细信息
     *
     * @param id 主键
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:query")
    @GetMapping("/{id}")
    @Operation(summary = "获取车辆年审明细详细信息")
    public R<HotVehicleAnnualReviewVo> getInfo(@NotNull(message = "主键不能为空")
                                               @PathVariable Long id) {
        return R.ok(hotVehicleAnnualReviewService.queryById(id));
    }

    /**
     * 新增车辆年审明细
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:add")
    @Log(title = "车辆年审明细", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    @Operation(summary = "新增车辆年审明细")
    public R<Void> add(@Validated(AddGroup.class) @RequestBody HotVehicleAnnualReviewBo bo) {
        return toAjax(hotVehicleAnnualReviewService.insertByBo(bo));
    }

    /**
     * 修改车辆年审明细
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:edit")
    @Log(title = "车辆年审明细", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    @Operation(summary = "修改车辆年审明细")
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody HotVehicleAnnualReviewBo bo) {
        return toAjax(hotVehicleAnnualReviewService.updateByBo(bo));
    }

    /**
     * 删除车辆年审明细
     *
     * @param ids 主键串
     */
    //@SaCheckPermission("resourceManagement:vehicleAnnualReview:remove")
    @Log(title = "车辆年审明细", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    @Operation(summary = "删除车辆年审明细")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable Long[] ids) {
        return toAjax(hotVehicleAnnualReviewService.deleteWithValidByIds(List.of(ids), true));
    }

    private static Date toDate(LocalDate date) {
        if (date == null) {
            return null;
        }
        return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    @GetMapping("/inspectionStatus/list")
    @Operation(summary = "车辆年审状态列表")
    public TableDataInfo<VehicleAnnualInspectionStatusVo> inspectionStatusList(HotVehicleStatusBo bo, PageQuery pageQuery) {
        Long companyId = bo != null ? bo.getCompanyId() : null;


        HotVehicleInspectionConfigBo configBo = new HotVehicleInspectionConfigBo();
        configBo.setCompanyId(companyId);
        configBo.setIsEnabled(1L);
        configBo.setIsDeleted(0L);
        List<HotVehicleInspectionConfigVo> configs = hotVehicleInspectionConfigService.queryList(configBo);
        configs = configs == null ? new ArrayList<>() : configs.stream()
                .filter(c -> c != null && (c.getIsEnabled() == null || c.getIsEnabled() == 1L))
                .sorted(Comparator.comparing(c -> c.getIntervalYears() == null ? Long.MAX_VALUE : c.getIntervalYears()))
                .toList();

        List<VehicleUtils.AnnualInspectionRule> rules = new ArrayList<>();
        for (HotVehicleInspectionConfigVo c : configs) {
            if (c.getIntervalYears() == null || c.getInspectionTimes() == null) {
                continue;
            }
            rules.add(new VehicleUtils.AnnualInspectionRule(c.getIntervalYears().intValue(), c.getInspectionTimes().intValue()));
        }

        if (bo == null) {
            bo = new HotVehicleStatusBo();
        }
        bo.setCompanyId(companyId);
        TableDataInfo<HotVehicleVo> vehiclePage = hotVehicleService.queryPageListByStatus(bo, pageQuery);
        List<HotVehicleVo> vehicles = vehiclePage.getRows();
        if (vehicles == null || vehicles.isEmpty()) {
            return new TableDataInfo<>(new ArrayList<>(), vehiclePage.getTotal());
        }

        LocalDate today = LocalDate.now();
        List<VehicleAnnualInspectionStatusVo> rows = new ArrayList<>();
        for (HotVehicleVo v : vehicles) {
            if (v == null) {
                continue;
            }
            VehicleAnnualInspectionStatusVo row = new VehicleAnnualInspectionStatusVo();
            row.setVehicleId(v.getId());
            row.setPlateNumber(v.getPlateNumber());
            row.setCompanyId(v.getCompanyId());
            row.setVehicleStatus(v.getVehicleStatus());
            row.setOperationStatus(v.getOperationStatus());

            Date issueDate = v.getCertificateIssueDate();
            row.setIssueDate(issueDate);

            HotVehicleAnnualReviewVo lastReview = v.getId() != null ? hotVehicleAnnualReviewService.queryLatestByVehicleId(v.getId()) : null;
            Date lastReviewDate = lastReview != null ? lastReview.getReviewDate() : null;
            row.setLastInspectionTime(lastReviewDate);

            LocalDate registrationDate = toLocalDate(v.getCertificateIssueDate());
            LocalDate lastInspectionDate = toLocalDate(lastReviewDate);

            VehicleUtils.InspectionResult result = VehicleUtils.calculateInspectionStatus(rules, registrationDate, lastInspectionDate);

            Integer times = result != null ? result.getInspectionTimes() : null;
            if (times != null) {
                if (times > 0) {
                    row.setInspectionTimesText("每年检测(" + times + "次)");
                } else {
                    row.setInspectionTimesText("无需年审");
                }
            }

            LocalDate dueLocalDate = result != null ? result.getNextInspectionDate() : null;

            row.setDueDate(toDate(dueLocalDate));

            if (result != null) {
                row.setWarningLevel(result.getWarningLevel());
                row.setWarningLevelText(result.getWarningLevelDesc());
                if (result.getWarningLevel() == 6) {
                    row.setInspectionTip("无需年审");
                } else if (result.getOverdueDays() > 0) {
                    row.setInspectionTip("已到期(" + result.getOverdueDays() + "天)");
                } else if (result.getRemainingDays() > 0) {
                    row.setInspectionTip("剩余(" + result.getRemainingDays() + "天)到期");
                }
            } else if (dueLocalDate != null) {
                long diff = ChronoUnit.DAYS.between(today, dueLocalDate);
                if (diff < 0) {
                    row.setInspectionTip("已到期(" + Math.abs(diff) + "天)");
                    row.setWarningLevel(1);
                    row.setWarningLevelText("一级预警");
                } else {
                    row.setInspectionTip("剩余(" + diff + "天)到期");
                }
            }

            rows.add(row);
        }

        return new TableDataInfo<>(rows, vehiclePage.getTotal());
    }

    private List<VehicleAnnualInspectionStatusVo> buildAnnualInspectionRows(List<HotVehicleVo> vehicles, List<VehicleUtils.AnnualInspectionRule> rules) {
        LocalDate today = LocalDate.now();
        List<VehicleAnnualInspectionStatusVo> rows = new ArrayList<>();
        for (HotVehicleVo v : vehicles) {
            if (v == null) {
                continue;
            }
            VehicleAnnualInspectionStatusVo row = new VehicleAnnualInspectionStatusVo();
            row.setVehicleId(v.getId());
            row.setPlateNumber(v.getPlateNumber());
            row.setCompanyId(v.getCompanyId());
            row.setVehicleStatus(v.getVehicleStatus());
            row.setOperationStatus(v.getOperationStatus());

            Date issueDate = v.getCertificateIssueDate();
            row.setIssueDate(issueDate);

            HotVehicleAnnualReviewVo lastReview = v.getId() != null ? hotVehicleAnnualReviewService.queryLatestByVehicleId(v.getId()) : null;
            Date lastReviewDate = lastReview != null ? lastReview.getReviewDate() : null;
            row.setLastInspectionTimeStr(lastReviewDate != null ? DateUtils.formatDate(lastReviewDate) : "未上传信息");
            row.setLastInspectionTime(lastReviewDate);

            LocalDate registrationDate = toLocalDate(v.getCertificateIssueDate());
            LocalDate lastInspectionDate = toLocalDate(lastReviewDate);
            VehicleUtils.InspectionResult result = VehicleUtils.calculateInspectionStatus(rules, registrationDate, lastInspectionDate);

            Integer times = result != null ? result.getInspectionTimes() : null;
            if (times != null) {
                if (times > 0) {
                    row.setInspectionTimesText("每年检测(" + times + "次)");
                } else {
                    row.setInspectionTimesText("无需年审");
                }
            }

            LocalDate dueLocalDate = result != null ? result.getNextInspectionDate() : null;
            row.setDueDate(toDate(dueLocalDate));

            if (result != null) {
                row.setWarningLevel(result.getWarningLevel());
                row.setWarningLevelText(result.getWarningLevelDesc());
                if (result.getWarningLevel() == 6) {
                    row.setInspectionTip("无需年审");
                } else if (result.getOverdueDays() > 0) {
                    row.setInspectionTip("已到期(" + result.getOverdueDays() + "天)");
                } else if (result.getRemainingDays() > 0) {
                    row.setInspectionTip("剩余(" + result.getRemainingDays() + "天)到期");
                }
            } else if (dueLocalDate != null) {
                long diff = ChronoUnit.DAYS.between(today, dueLocalDate);
                if (diff < 0) {
                    row.setInspectionTip("已到期(" + Math.abs(diff) + "天)");
                    row.setWarningLevel(1);
                    row.setWarningLevelText("一级预警");
                } else {
                    row.setInspectionTip("剩余(" + diff + "天)到期");
                }
            }
            rows.add(row);
        }
        return rows;
    }

    @Data
    @ExcelIgnoreUnannotated
    public static class VehicleAnnualInspectionStatusVo {
        @ExcelIgnore
        private Long companyId;

        @ExcelIgnore
        private String vehicleId;

        @ExcelProperty(value = "车牌号", index = 0)
        private String plateNumber;

        @ExcelProperty(value = "每年年检次数", index = 1)
        private String inspectionTimesText;

        @ExcelProperty(value = "年检提示", index = 2)
        private String inspectionTip;

        @ExcelIgnore
        private Date lastInspectionTime;

        @ExcelProperty(value = "最近年检时间", index = 3)
        private String lastInspectionTimeStr;

        @ExcelProperty(value = "行驶证发证日期", index = 4)
        private Date issueDate;

        @ExcelProperty(value = "到期日期", index = 5)
        private Date dueDate;

        @ExcelIgnore
        private Integer warningLevel;

        @ExcelProperty(value = "提示等级", index = 6)
        private String warningLevelText;

        @ExcelIgnore
        private Long vehicleStatus;

        @ExcelIgnore
        private Long operationStatus;
    }
}
