package com.cool.store.service.tp.impl;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.tp.TpRuleDAO;
import com.cool.store.dto.tp.TpPenaltyImportErrorDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.tp.TpRuleDO;
import com.cool.store.exception.ServiceException;
import com.cool.store.oss.OssClientService;
import com.cool.store.request.tp.TpApplyRequest;
import com.cool.store.request.tp.TpPenaltyImportRowDTO;
import com.cool.store.service.tp.TpApplyService;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.UUIDUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.xssf.usermodel.*;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 扣分申请单导入监听器
 */
@RequiredArgsConstructor
@Slf4j
public class TpPenaltyImportListener implements ReadListener<TpPenaltyImportRowDTO> {

    /**
     * 证明图片起始列索引（从0开始，G列=6）
     */
    private static final int IMAGE_COL_START_INDEX = 6;
    /**
     * 证明图片结束列索引（L列=11）
     */
    private static final int IMAGE_COL_END_INDEX = 11;
    /**
     * 每行最多图片数量
     */
    private static final int MAX_IMAGE_PER_ROW = 6;

    private final TpApplyService tpApplyService;
    private final TpRuleDAO tpRuleDAO;
    private final StoreDao storeDao;
    private final OssClientService ossClientService;
    private final List<TpPenaltyImportErrorDTO> errorList;
    private final LoginUserInfo user;
    private final byte[] excelBytes;
    private final AtomicInteger totalNum;
    private final AtomicInteger successNum;

    private final Map<Integer, List<String>> pictureMap = new HashMap<>();
    private volatile boolean pictureParsed = false;


    @Override
    public void onException(Exception e, AnalysisContext analysisContext) {
        log.error("导入失败", e);
    }

    @Override
    public void invokeHead(Map<Integer, CellData> map, AnalysisContext analysisContext) {
        // head会回调多次，图片解析只做一次
        if (pictureParsed) {
            return;
        }
        try {
            XSSFWorkbook book = new XSSFWorkbook(new ByteArrayInputStream(excelBytes));
            XSSFSheet sheet = book.getSheetAt(0);
            if (Objects.isNull(sheet)) {
                log.error("读取失败");
            }

            // 获取所有图片
            XSSFDrawing drawingPatriarch = sheet.getDrawingPatriarch();
            if (Objects.isNull(drawingPatriarch)) {
                throw new RuntimeException("excel表格中没有图片，请补充");
            }
            List<XSSFShape> shapes = drawingPatriarch.getShapes();
            if (CollectionUtils.isEmpty(shapes)) {
                log.info("表格中没有图片");
            }
            List<XSSFPicture> pictures = shapes.stream()
                    .filter(shape -> shape instanceof XSSFPicture)
                    .map(shape -> (XSSFPicture) shape)
                    .collect(Collectors.toList());
            if (pictures.isEmpty()) {
                return;
            }

            // 查找指定单元格中的图片
            String fileNamePrefix = UUIDUtils.get32UUID();
            for (XSSFPicture picture : pictures) {
                ClientAnchor anchor = picture.getPreferredSize();
                int row = anchor.getRow1();
                int col = anchor.getCol1();
                // 检查图片是否在指定单元格中
                if (IMAGE_COL_START_INDEX <= col && col <= IMAGE_COL_END_INDEX) {
                    XSSFPictureData pictureData = picture.getPictureData();
                    byte[] data = pictureData.getData();
                    // 获取图片后缀
                    String fileName = fileNamePrefix + "-" + (row + 1) + "-" + (col + 1) + ".jpg";
                    try (InputStream in = new ByteArrayInputStream(data)) {
                        String url = ossClientService.putObjectWithoutPrefix(fileName, in, (long) data.length, "image/jpeg");
                        pictureMap.compute(row, (key, value) -> {
                            if (value == null) {
                                value = new ArrayList<>();
                            }
                            value.add(url);
                            return value;
                        });
                    } catch (Exception e) {
                        log.error("第{}行图片上传失败", row + 1, e);
                    }
                }
            }
            pictureParsed = true;
        } catch (Exception e) {
            log.error("图片解析失败", e);
        }
    }

    @Override
    public void invoke(TpPenaltyImportRowDTO data, AnalysisContext context) {
        totalNum.incrementAndGet();
        int rowIndex = context.readRowHolder().getRowIndex();

        // 基础必填校验
        if (data == null) {
            return;
        }
        if (data.getStoreNum() == null || data.getStoreNum().trim().isEmpty()) {
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "门店编码为空"));
            return;
        }
        if (data.getRuleNo() == null || data.getRuleNo().trim().isEmpty()) {
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "行惩处规则编码为空"));
            return;
        }

        // 根据门店编码查询门店
        StoreDO store = storeDao.getByStoreNum(data.getStoreNum());
        if (store == null) {
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "门店编码不存在"));
            return;
        }

        // 根据规则编码查询规则
        TpRuleDO rule = tpRuleDAO.getEnableByCode(data.getRuleNo());
        if (rule == null) {
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "惩处规则编码不存在"));
            return;
        }

        TpApplyRequest request = new TpApplyRequest();
        request.setStoreId(store.getStoreId());
        request.setRuleId(rule.getId());
        request.setRemark(data.getRemark());
        request.setIsDraft(0);
        request.setSource(0);
        request.setApplyUserId(user.getUserId());
        request.setApplyUserName(user.getName());
        List<String> proofUrls = pictureMap.getOrDefault(rowIndex, Collections.emptyList());
        request.setProofUrls(String.join(",", proofUrls.subList(0, Math.min(proofUrls.size(), MAX_IMAGE_PER_ROW))));
        request.setScore(data.getScore());
        request.setAmount(data.getAmount());
        if (Objects.nonNull(data.getAppealDeadline())) {
            request.setAppealEndDate(CoolDateUtils.localDate2Date(LocalDate.now().plusDays(data.getAppealDeadline())));
        }
        try {
            tpApplyService.penaltyApplySubmit(request);
            successNum.incrementAndGet();
        } catch (ServiceException e) {
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), e.getErrorMessage()));
        } catch (Exception e) {
            log.error("申请单创建失败", e);
            errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "数据异常"));
        }
    }

    @Override
    public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // ignore
    }

    @Override
    public boolean hasNext(AnalysisContext analysisContext) {
        return true;
    }
}


