package com.retdata.yaoyibi.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.retdata.yaoyibi.domain.*;
import com.retdata.yaoyibi.mapper.SysImplPlanMapper;
import com.retdata.yaoyibi.service.CsoSysDictItemService;
import com.retdata.yaoyibi.service.SysImplPlanService;
import com.retdata.yaoyibi.service.WmDaDrugEntDrugtableService;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.enums.DataSourceType;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;

@Service
@Transactional(readOnly = true)
@DataSource(DataSourceType.CSO)
public class SysImplPlanServiceImpl extends ServiceImpl<SysImplPlanMapper, SysImplPlan> implements SysImplPlanService {

    private final WmDaDrugEntDrugtableService wmDaDrugEntDrugtableService;

    private final CsoSysDictItemService csoSysDictItemService;

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public SysImplPlanServiceImpl(WmDaDrugEntDrugtableService wmDaDrugEntDrugtableService, CsoSysDictItemService csoSysDictItemService) {
        this.wmDaDrugEntDrugtableService = wmDaDrugEntDrugtableService;
        this.csoSysDictItemService = csoSysDictItemService;
    }

    @Override
    public Page<SysImplPlanSearchDto> search(SysImplPlanSearchParams searchParams, Pageable pageable) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<SysImplPlanSearchDto> page =
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                        pageable.getPageNumber() + 1, pageable.getPageSize());
        page = getBaseMapper().selectPageByParams(page, searchParams);
        if (page.getRecords().isEmpty()) {
            return new PageImpl<>(page.getRecords(), pageable, page.getTotal());
        }
        Map<Integer, WmDaDrugEntDrugtableSummary> drugEntDrugtableMap = new HashMap<>();
        for (SysImplPlanSearchDto dto : page.getRecords()) {
            processPlanState(dto);
            wmDaDrugEntDrugtableService.parseDrugtable(dto.getSku(), drugEntDrugtableMap);
        }
        // 获取药品信息
        if (!drugEntDrugtableMap.isEmpty()) {
            List<WmDaDrugEntDrugtableSummary> drugtableSummaries = wmDaDrugEntDrugtableService.batchFetchDrugs(drugEntDrugtableMap.keySet());
            for (WmDaDrugEntDrugtableSummary drugtableSummary : drugtableSummaries) {
                drugEntDrugtableMap.put(drugtableSummary.getId(), drugtableSummary);
            }
        }
        for (SysImplPlanSearchDto dto : page.getRecords()) {
            String[] drugInfo = wmDaDrugEntDrugtableService.getDrugtableInfo(dto.getSku(), drugEntDrugtableMap);
            dto.setSku(drugInfo[0]);
        }
        return new PageImpl<>(page.getRecords(), pageable, page.getTotal());
    }

    private static void processPlanState(SysImplPlanSearchDto dto) {
        if ("IN_PROGRESS".equals(dto.getPlanState()) && dto.getPlanExpiry() != null && dto.getPlanExpiry().isBefore(LocalDate.now())) {
            dto.setPlanState("ENDED");
        }
    }

    @Override
    public List<CsoSysDeptSummary> listConsignees() {
        return getBaseMapper().selectConsignees();
    }

    @Override
    public List<CsoSysDeptSummary> listConsignors() {
        return getBaseMapper().selectConsignors();
    }

    @Override
    public XSSFWorkbook export(SysImplPlanSearchParams searchParams) {
        List<SysImplPlanExportDto> exportDtoList = getBaseMapper().selectExportData(searchParams);
        Map<Long, SysImplPlanExportDto> exportDtoCache = new HashMap<>(exportDtoList.size());
        MultiValueMap<Long, SysImplPlanExportDto> parentToChildren = new LinkedMultiValueMap<>();
        for (SysImplPlanExportDto dto : exportDtoList) {
            exportDtoCache.put(dto.getPlanId(), dto);
            if (dto.getParentId() != null && dto.getParentId() != 0) {
                parentToChildren.add(dto.getParentId(), dto);
            }
        }
        // 获取所有上级包
        Set<Long> toFetchParentIds = new HashSet<>(parentToChildren.keySet());
        toFetchParentIds.removeAll(exportDtoCache.keySet());
        while (!toFetchParentIds.isEmpty()) {
            List<SysImplPlanExportDto> parentList = batchFetchExportDto(toFetchParentIds);
            toFetchParentIds.clear();
            parentList.forEach(parent -> {
                exportDtoCache.put(parent.getPlanId(), parent);
                if (parent.getParentId() != null && parent.getParentId() != 0) {
                    if (!exportDtoCache.containsKey(parent.getParentId())) {
                        toFetchParentIds.add(parent.getParentId());
                    }
                }
            });
        }
        // 只导出叶子节点
        List<SysImplPlanExportRecord> exportRecords = new ArrayList<>(exportDtoList.size());
        Map<Integer, WmDaDrugEntDrugtableSummary> drugEntDrugtableMap = new HashMap<>();
        for (SysImplPlanExportDto dto : exportDtoList) {
            if (parentToChildren.containsKey(dto.getPlanId())) {
                continue;// 跳过非叶子节点
            }
            processPlanState(dto);
            wmDaDrugEntDrugtableService.parseDrugtable(dto.getSku(), drugEntDrugtableMap);
            SysImplPlanExportRecord exportRecord = new SysImplPlanExportRecord();
            if (dto.getParentId() == null || dto.getParentId() == 0) {
                exportRecord.setRootPlan(dto);
            } else {
                exportRecord.setFirstAgentPlan(dto);
                exportRecord.setRootPlan(exportDtoCache.get(dto.getParentId()));
            }
            exportRecords.add(exportRecord);
        }
        // 获取药品信息
        if (!drugEntDrugtableMap.isEmpty()) {
            List<WmDaDrugEntDrugtableSummary> drugtableSummaries = wmDaDrugEntDrugtableService.batchFetchDrugs(drugEntDrugtableMap.keySet());
            for (WmDaDrugEntDrugtableSummary drugtableSummary : drugtableSummaries) {
                drugEntDrugtableMap.put(drugtableSummary.getId(), drugtableSummary);
            }
        }
        // 创建xlsx
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("计划包数据");
        int rowNo = 0;
        int columnNo = 0;
        // 创建表头
        XSSFRow row = sheet.createRow(rowNo++);
        String[] headers = {"药企计划包名称", "计划分值", "计划周期", "来源对象", "承接对象", "推广药品", "下发状态", "拆解状态", "创建时间", "待拆解分值", "已拆解分值",
                "一级代理商计划包名称", "计划分值", "计划周期", "来源对象", "承接对象", "推广药品", "下发状态", "拆解状态", "创建时间", "待拆解分值", "已拆解分值"};
        for (String header : headers) {
            row.createCell(columnNo++).setCellValue(header);
        }
        if (!exportRecords.isEmpty()) {
            Map<String, String> planStateDict = csoSysDictItemService.getDictMap("plan_state");
            Map<String, String> disassembleStateDict = csoSysDictItemService.getDictMap("disassemble_state");
            for (SysImplPlanExportRecord exportRecord : exportRecords) {
                row = sheet.createRow(rowNo++);
                columnNo = 0;
                for (SysImplPlanExportDto dto : Arrays.asList(exportRecord.getRootPlan(), exportRecord.getFirstAgentPlan())) {
                    if (dto == null) {
                        columnNo += 11;
                        continue;
                    }
                    row.createCell(columnNo++).setCellValue(dto.getPlanName());
                    row.createCell(columnNo++).setCellValue(dto.getPlanScore().toString());
                    row.createCell(columnNo++).setCellValue(dto.getPlanIssue() + "至" + dto.getPlanExpiry());
                    row.createCell(columnNo++).setCellValue(dto.getConsignor() == null ? "" : dto.getConsignor().getName());
                    row.createCell(columnNo++).setCellValue(dto.getConsignee() == null ? "" : dto.getConsignee().getName());
                    String[] drugInfo = wmDaDrugEntDrugtableService.getDrugtableInfo(dto.getSku(), drugEntDrugtableMap);
                    row.createCell(columnNo++).setCellValue(drugInfo[0]);
                    row.createCell(columnNo++).setCellValue(planStateDict.getOrDefault(dto.getPlanState(), dto.getPlanState()));
                    row.createCell(columnNo++).setCellValue(disassembleStateDict.getOrDefault(dto.getDisassembleState(), dto.getDisassembleState()));
                    row.createCell(columnNo++).setCellValue(DATE_FORMAT.format(dto.getCreateTime()));
                    row.createCell(columnNo++).setCellValue(dto.getAvailScore().toString());
                    row.createCell(columnNo++).setCellValue(dto.getDisassembleScore() == null ? "" : dto.getDisassembleScore().toString());
                }
            }
        }
        return workbook;
    }

    private List<SysImplPlanExportDto> batchFetchExportDto(Collection<Long> planIds) {
        List<Long> batchIds = new ArrayList<>(planIds);
        List<SysImplPlanExportDto> result = new ArrayList<>(planIds.size());
        int batchSize = 1000;
        for (int i = 0; i < batchIds.size(); i += batchSize) {
            int end = Math.min(i + batchSize, batchIds.size());
            List<SysImplPlanExportDto> batchResult = getBaseMapper().selectExportDtoByPlanIds(batchIds.subList(i, end));
            result.addAll(batchResult);
        }
        return result;
    }

    private static void processPlanState(SysImplPlanExportDto dto) {
        if ("IN_PROGRESS".equals(dto.getPlanState()) && dto.getPlanExpiry() != null && dto.getPlanExpiry().isBefore(LocalDate.now())) {
            dto.setPlanState("ENDED");
        }
    }
}
