package com.hotwj.platform.reportStatistics.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.reportStatistics.domain.bo.ReportLedgerQueryBo;
import com.hotwj.platform.reportStatistics.domain.vo.*;
import com.hotwj.platform.reportStatistics.mapper.LedgerReportMapper;
import com.hotwj.platform.reportStatistics.service.ILedgerReportService;
import com.hotwj.platform.resourceManagement.company.domain.vo.SysCompanyVo;
import com.hotwj.platform.resourceManagement.company.service.ISysCompanyService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 驾驶员台账服务接口实现类
 *
 * @author shihongwei
 * @date 2026-01-06
 */
@Service
@RequiredArgsConstructor
public class LedgerReportServiceImpl implements ILedgerReportService {

    private final LedgerReportMapper ledgerReportMapper;
    private final ISysCompanyService sysCompanyService;

    @Override
    public TableDataInfo<DriverInfoLedgerVo> queryDriverInfo(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<DriverInfoLedgerVo> page = pageQuery.build();
        List<DriverInfoLedgerVo> rows = ledgerReportMapper.selectDriverInfoPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<GovViolationHandlingLedgerVo> queryGovViolationHandlingLedger(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovViolationHandlingLedgerVo> page = pageQuery.build();
        List<GovViolationHandlingLedgerVo> rows = ledgerReportMapper.selectGovViolationHandlingPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<DriverInfoLedgerVo> listDriverInfo(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectDriverInfoList(districtCode, bo);
    }

    @Override
    public TableDataInfo<DriverHealthLedgerVo> queryDriverHealth(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<DriverHealthLedgerVo> page = pageQuery.build();
        List<DriverHealthLedgerVo> rows = ledgerReportMapper.selectDriverHealthPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<DriverHealthLedgerVo> listDriverHealth(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectDriverHealthList(districtCode, bo);
    }

    @Override
    public TableDataInfo<ProfCertScoreLedgerVo> queryProfCertScore(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<ProfCertScoreLedgerVo> page = pageQuery.build();
        List<ProfCertScoreLedgerVo> rows = ledgerReportMapper.selectProfCertScorePage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<ProfCertScoreLedgerVo> listProfCertScore(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectProfCertScoreList(districtCode, bo);
    }

    @Override
    public TableDataInfo<DriverIntegrityLedgerVo> queryDriverIntegrity(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<DriverIntegrityLedgerVo> page = pageQuery.build();
        List<DriverIntegrityLedgerVo> rows = ledgerReportMapper.selectDriverIntegrityPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<DriverIntegrityLedgerVo> listDriverIntegrity(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectDriverIntegrityList(districtCode, bo);
    }

    @Override
    public TableDataInfo<VehicleInfoLedgerVo> queryVehicleInfo(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<VehicleInfoLedgerVo> page = pageQuery.build();
        List<VehicleInfoLedgerVo> rows = ledgerReportMapper.selectVehicleInfoPage(page, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<VehicleInfoLedgerVo> listVehicleInfo(ReportLedgerQueryBo bo) {
        List<VehicleInfoLedgerVo> list = ledgerReportMapper.selectVehicleInfoList(bo);
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                list.get(i).setIndex(i + 1);
            }
        }
        return list;
    }

    @Override
    public TableDataInfo<GovVehicleInfoLedgerVo> queryGovVehicleInfo(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovVehicleInfoLedgerVo> page = pageQuery.build();
        List<GovVehicleInfoLedgerVo> rows = ledgerReportMapper.selectGovVehicleInfoPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<GovVehicleInfoLedgerVo> listGovVehicleInfo(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectGovVehicleInfoList(districtCode, bo);
    }

    @Override
    public TableDataInfo<GovGpsViolationLedgerVo> queryGovGpsViolation(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        bo.setNeedInterview(1);
        bo.setProcessStatus(2);
        Page<GovGpsViolationLedgerVo> page = pageQuery.build();
        List<GovGpsViolationLedgerVo> rows = ledgerReportMapper.selectGovGpsViolationPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<AccidentLedgerVo> queryAccident(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<AccidentLedgerVo> page = pageQuery.build();
        List<AccidentLedgerVo> rows = ledgerReportMapper.selectAccidentPage(page, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<AccidentLedgerVo> listAccident(ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectAccidentList(bo);
    }

    @Override
    public TableDataInfo<GovAccidentLedgerVo> queryGovAccident(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovAccidentLedgerVo> page = pageQuery.build();
        List<GovAccidentLedgerVo> rows = ledgerReportMapper.selectGovAccidentPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<GovAccidentLedgerVo> listGovAccident(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectGovAccidentList(districtCode, bo);
    }

    @Override
    public TableDataInfo<PreJobTrainingLedgerVo> queryPreJobTraining(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<PreJobTrainingLedgerVo> page = pageQuery.build();
        List<PreJobTrainingLedgerVo> rows = ledgerReportMapper.selectPreJobTrainingPage(page, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<PreJobTrainingLedgerVo> listPreJobTraining(ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectPreJobTrainingList(bo);
    }

    @Override
    public TableDataInfo<GovPreJobTrainingLedgerVo> queryGovPreJobTraining(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovPreJobTrainingLedgerVo> page = pageQuery.build();
        List<GovPreJobTrainingLedgerVo> rows = ledgerReportMapper.selectGovPreJobTrainingPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public List<GovPreJobTrainingLedgerVo> listGovPreJobTraining(String districtCode, ReportLedgerQueryBo bo) {
        return ledgerReportMapper.selectGovPreJobTrainingList(districtCode, bo);
    }

    @Override
    public TableDataInfo<GovPreJobTrainingDetailVo> queryGovPreJobTrainingDetail(String districtCode, ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovPreJobTrainingDetailVo> page = pageQuery.build();
        List<GovPreJobTrainingDetailVo> rows = ledgerReportMapper.selectGovPreJobTrainingDetailPage(page, districtCode, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<GovSafetyEducationTrainingVo> queryGovSafetyEducationTraining(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<GovSafetyEducationTrainingVo> page = pageQuery.build();
        List<GovSafetyEducationTrainingVo> rows = ledgerReportMapper.selectGovSafetyEducationTrainingPage(page, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public GovSafetyEducationTrainingDetailVo queryGovSafetyEducationTrainingDetail(Long id) {
        // 1. Get main details
        GovSafetyEducationTrainingDetailVo detail = ledgerReportMapper.selectGovSafetyEducationTrainingDetail(id);
        if (detail == null) {
            return null;
        }

        // 2. Get participants
        detail.setParticipantList(ledgerReportMapper.selectGovSafetyEducationTrainingParticipants(id));

        // 3. Get course names and format content
        List<String> courseNames = ledgerReportMapper.selectGovSafetyEducationTrainingCourseNames(id);
        if (courseNames != null && !courseNames.isEmpty()) {
            String content = IntStream.range(0, courseNames.size())
                    .mapToObj(i -> (i + 1) + "：" + courseNames.get(i))
                    .collect(Collectors.joining("\n"));
            detail.setTrainingContent(content);
        }

        return detail;
    }

    @Override
    public TableDataInfo<GovViolationInfoLedgerVo> queryGovViolationInfoLedger(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        // 1. Get company creation time
        SysCompanyVo company = sysCompanyService.queryById(bo.getCompanyId());
        if (company == null) {
            return TableDataInfo.build();
        }

        // 2. Determine start and end YearMonth
        LocalDate createDate = company.getCreateTime() != null
                ? company.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
                : LocalDate.now().minusYears(1); // Fallback
        YearMonth startYm = YearMonth.from(createDate);
        YearMonth endYm = YearMonth.now();

        if (startYm.isAfter(endYm)) {
            startYm = endYm;
        }

        // 3. Generate all YearMonths in descending order (newest first)
        List<String> allMonths = new ArrayList<>();
        YearMonth current = endYm;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M");

        while (!current.isBefore(startYm)) {
            allMonths.add(current.format(formatter));
            current = current.minusMonths(1);
        }

        // 4. Pagination in memory
        int total = allMonths.size();
        int pageNum = pageQuery.getPageNum();
        int pageSize = pageQuery.getPageSize();
        int start = (pageNum - 1) * pageSize;
        int end = Math.min(start + pageSize, total);

        if (start >= total) {
            TableDataInfo<GovViolationInfoLedgerVo> emptyPage = TableDataInfo.build();
            emptyPage.setTotal(total);
            emptyPage.setRows(Collections.emptyList());
            return emptyPage;
        }

        List<String> pagedMonths = allMonths.subList(start, end);

        // 5. Query counts for the paged months
        // Convert first and last month of the page to Date range for query optimization
        // Note: pagedMonths is descending, so first element is the latest month (end of query range)
        // last element is the oldest month (start of query range)
        String latestMonthStr = pagedMonths.get(0);
        String oldestMonthStr = pagedMonths.get(pagedMonths.size() - 1);

        YearMonth queryEndYm = YearMonth.parse(latestMonthStr, formatter);
        YearMonth queryStartYm = YearMonth.parse(oldestMonthStr, formatter);

        Date queryStartDate = Date.from(queryStartYm.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date queryEndDate = Date.from(queryEndYm.atEndOfMonth().atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());

        List<GovViolationInfoLedgerVo> counts = ledgerReportMapper.selectViolationCountByDateRange(bo, queryStartDate, queryEndDate);
        Map<String, Long> countMap = counts.stream()
                .collect(Collectors.toMap(GovViolationInfoLedgerVo::getPlanName, GovViolationInfoLedgerVo::getViolationCount));

        // 6. Build result list
        List<GovViolationInfoLedgerVo> result = pagedMonths.stream()
                .map(month -> {
                    GovViolationInfoLedgerVo vo = new GovViolationInfoLedgerVo();
                    vo.setPlanName(month);
                    vo.setViolationCount(countMap.getOrDefault(month, 0L));
                    return vo;
                })
                .collect(Collectors.toList());

        TableDataInfo<GovViolationInfoLedgerVo> tableData = TableDataInfo.build();
        tableData.setRows(result);
        tableData.setTotal(total);
        return tableData;
    }

    @Override
    public TableDataInfo<GovViolationInfoDetailVo> queryGovViolationInfoDetail(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        if (bo.getEndDate() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(bo.getEndDate());
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            bo.setEndDate(calendar.getTime());
        }
        Page<GovViolationInfoDetailVo> page = pageQuery.build();
        List<GovViolationInfoDetailVo> rows = ledgerReportMapper.selectGovViolationInfoDetailPage(page, bo);
        page.setRecords(rows);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<SafetyProductionMeetingLedgerVo> querySafetyProductionMeeting(ReportLedgerQueryBo bo, PageQuery pageQuery) {
        Page<SafetyProductionMeetingLedgerVo> page = pageQuery.build();
        List<SafetyProductionMeetingLedgerVo> list = ledgerReportMapper.selectSafetyProductionMeetingPage(page, bo);
        page.setRecords(list);
        return TableDataInfo.build(page);
    }
}
