package cn.newfeifan.mall.module.distri.service.ptsettlement;

import cn.hutool.core.io.IoUtil;
import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementRespVO;
import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.ShopSettlementDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementErrorData;
import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.file.BufferedImageMultipartFile;
import cn.newfeifan.mall.module.distri.enums.PtSettlemntStatusEnum;
import cn.newfeifan.mall.module.distri.service.shopsettlement.ShopSettlementService;
import cn.newfeifan.mall.module.infra.service.file.FileService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptsettlement.PtSettlementDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.ptsettlement.PtSettlementMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

import org.springframework.web.multipart.MultipartFile;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;

import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;


/**
 * 平台每日结算信息表，记录店铺的结算信息 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class PtSettlementServiceImpl implements PtSettlementService {

    @Resource
    private PtSettlementMapper ptSettlementMapper;

    @Resource
    private ShopSettlementService shopSettlementService;

    @Resource
    private FileService fileService;

    @Override
    public Long createPtSettlement(PtSettlementSaveReqVO createReqVO) {
        // 插入
        PtSettlementDO ptSettlement = BeanUtils.toBean(createReqVO, PtSettlementDO.class);
        ptSettlementMapper.insert(ptSettlement);
        // 返回
        return ptSettlement.getId();
    }

    @Override
    public void updatePtSettlement(PtSettlementSaveReqVO updateReqVO) {
        // 校验存在
        validatePtSettlementExists(updateReqVO.getId());
        // 更新
        PtSettlementDO updateObj = BeanUtils.toBean(updateReqVO, PtSettlementDO.class);
        ptSettlementMapper.updateById(updateObj);
    }

    @Override
    public void deletePtSettlement(Long id) {
        // 校验存在
        validatePtSettlementExists(id);
        // 删除
        ptSettlementMapper.deleteById(id);
    }

    private void validatePtSettlementExists(Long id) {
        if (ptSettlementMapper.selectById(id) == null) {
            throw exception(PT_SETTLEMENT_NOT_EXISTS);
        }
    }

    @Override
    public PtSettlementDO getPtSettlement(Long id) {
        return ptSettlementMapper.selectById(id);
    }

    @Override
    public PageResult<PtSettlementDO> getPtSettlementPage(PtSettlementPageReqVO pageReqVO) {
        PageResult<PtSettlementDO> result = ptSettlementMapper.selectPage(pageReqVO);

        for (PtSettlementDO ptSettlementDO : result.getList()) {
            ptSettlementDO.setCreateTime(ptSettlementDO.getCreateTime().minusDays(1));
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ShopSettlementErrorData> importPdf(MultipartFile multipartFile, Long id) {
        // 定义日期格式，只包含年月日
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 校验文件格式
        if (!isPdf(multipartFile)) {
            ErrorCode ERROR = new ErrorCode(1_002_030_026, "选择的文件不是pdf格式");
            throw exception(ERROR);
        }

        // 获取选择日期,店铺的结算信息
        List<ShopSettlementDO> shopSettList = shopSettlementService.selectListByPtId(id);

        if (shopSettList.isEmpty()) {
            ErrorCode ERROR = new ErrorCode(1_002_030_027, "选择的行中没有结算单记录");
            throw exception(ERROR);
        }

        // 用来记录错误的回执单信息
        List<ShopSettlementErrorData> errorList = new ArrayList<>();

        try {
            // 将MultipartFile转换为临时文件
            Path tempFile = Files.createTempFile("temp", ".pdf");
            multipartFile.transferTo(tempFile.toFile());

            // 加载指定路径的PDF文档
            PDDocument document = PDDocument.load(tempFile.toFile());

            if(document.getNumberOfPages() == 0){
                ErrorCode ERROR = new ErrorCode(1_002_030_028, "选择的文件是空的");
                throw exception(ERROR);
            }

            // 创建PDF渲染器，用于将PDF页面渲染为图像
            PDFRenderer pdfRenderer = new PDFRenderer(document);

            // 创建PDF文本剥离器，用于从PDF页面中提取文本
            PDFTextStripper textStripper = new PDFTextStripper();

            // 遍历文档中的每一页
            for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {

                // 设置开始和结束页码，以便仅从当前页提取文本
                textStripper.setStartPage(pageIndex + 1);
                textStripper.setEndPage(pageIndex + 1);

                // 提取当前页的文本
                String pageText = textStripper.getText(document);

                // 检查页面是否包含错误信息
                if (containsErrorInfo(pageText)) {

                    // 账号
                    String accountNumber = getErrorAccountNumber(pageText, true);
                    // 户名
                    String accountName = getErrorAccountName(pageText, true);
                    // 金额
                    String money = getMoney(pageText);
                    // 订单流水号
                    String orderNO = getOrderNO(pageText);

                    ShopSettlementErrorData error = ShopSettlementErrorData.builder()
                            .accountNumber(accountNumber)
                            .accountName(accountName)
                            .money(money)
                            .orderNO(orderNO)
                            .build();

                    errorList.add(error);
                    continue;
                }

                // 判断备注的账单日期是否与结算单为同一天
                String time = getOrderTime(pageText);
                if (time != null && !time.isEmpty()) {
                    for (ShopSettlementDO shopSettlement : shopSettList) {
                        // 判断日期是否同样
                        isSameDate(shopSettlement, formatter, time);
                    }
                }

                for (ShopSettlementDO shopSettlement : shopSettList) {
                    // 账号
                    String accountNumber = getErrorAccountNumber(pageText, false);
                    // 户名
                    String accountName = getErrorAccountName(pageText, false);
                    // 金额
                    String money = getMoney(pageText);

                    if (shopSettlement.getAccountNumber().equals(accountNumber) &&
                            shopSettlement.getAccountName().equals(accountName) &&
                            shopSettlement.getShopTotalHighAmount().divide(new BigDecimal("100"), 2, RoundingMode.FLOOR).toString().equals(money)) {

                        BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 300);
                        int desiredHeight = 1200; // 设定你想要的高度

                        // 获取原始宽度和高度
                        int originalWidth = image.getWidth();
                        int originalHeight = image.getHeight();

                        // 计算裁剪区域的宽度和高度
                        int cropWidth = originalWidth;
                        int cropHeight = desiredHeight;

                        // 确保裁剪区域不会超出原图范围
                        if (cropHeight > originalHeight) {
                            cropHeight = originalHeight;
                        }

                        // 计算裁剪区域的起始点，这里我们假设从顶部开始裁剪
                        int x = 0;
                        int y = 0;

                        // 裁剪图片
                        BufferedImage croppedImage = image.getSubimage(x, y, cropWidth, cropHeight);

                        String fileName = "image.png";
                        String contentType = "image/png";

                        MultipartFile file = new BufferedImageMultipartFile(croppedImage, fileName, contentType);

                        // 上传文件
                        String fileUrl = fileService.createFile(file.getOriginalFilename(), null, IoUtil.readBytes(file.getInputStream()));

                        ShopSettlementSaveReqVO bean = BeanUtils.toBean(shopSettlement, ShopSettlementSaveReqVO.class);
                        bean.setAttachment(fileUrl);

                        // 保存修改结算单
                        shopSettlementService.updateShopSettlement(bean);
                    }
                }
            }

            // 回退错误的回执单导致的结算单信息
            if (!errorList.isEmpty()) {

                for (ShopSettlementErrorData shopSettlementErrorData : errorList) {

                    for (ShopSettlementDO shopSettlement : shopSettList) {

                        if (shopSettlement.getAccountNumber().equals(shopSettlementErrorData.getAccountNumber()) &&
                                shopSettlement.getAccountName().equals(shopSettlementErrorData.getAccountName()) &&
                                shopSettlement.getShopTotalHighAmount().divide(new BigDecimal("100"), 2, RoundingMode.FLOOR).toString().equals(shopSettlementErrorData.getMoney())
                        ) {
                            ShopSettlementSaveReqVO bean = BeanUtils.toBean(shopSettlement, ShopSettlementSaveReqVO.class);
                            bean.setAttachment(null);

                            shopSettlementErrorData.setShopSettlement(BeanUtils.toBean(bean, ShopSettlementRespVO.class));

                            shopSettlementService.updateShopSettlement(bean);
                        }
                    }
                }
            }

            boolean status = true;
            for (ShopSettlementDO shopSettlement : shopSettList) {
                if (shopSettlement.getAttachment() == null) {
                    status = false;
                }
            }

            PtSettlementDO ptSettlementDO = ptSettlementMapper.selectById(id);
            if (status) {
                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT.getStatus());
            } else {
                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_ERROR.getStatus());
            }

            // 如果错误的回执单数量和结算单数量一致，则说明全部失败
            if (errorList.size() == shopSettList.size()) {
                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_SUCCESS.getStatus());
            }

            // 更新pt结算单状态
            ptSettlementMapper.updateById(ptSettlementDO);

            // 关闭PDF文档
            document.close();
        } catch (Exception e) {
            String message = e.getMessage();
            if(e.getMessage().equals("String index out of range: -1")){
                message = "上传的PDF文件内容不正确！";
            }

            ErrorCode ERROR = new ErrorCode(1_002_030_027, "处理PDF文件异常: " + message);
            throw exception(ERROR);
        }

        return errorList;
    }

    /**
     * 判断备注的账单日期是否与结算单为同一天
     *
     * @param shopSettlement 结算单
     * @param formatter             日期格式
     * @param time                  日期
     */
    private void isSameDate(ShopSettlementDO shopSettlement, DateTimeFormatter formatter, String time) {
        // 使用定义的格式器格式化LocalDateTime对象
        String formattedDate = shopSettlement.getCreateTime().minusDays(1).format(formatter);

        if (!time.equals(formattedDate)) {
            ErrorCode ERROR = new ErrorCode(1_002_030_028, "上传的PDF文件中有回执单日期与结算单日期不同!");
            throw exception(ERROR);
        }
    }

    /**
     * 获取回执单的备注:账单日期
     *
     * @param pageText 回执单文本
     * @return 账单日期
     */
    private String getOrderTime(String pageText) {
        int timeIndex = pageText.indexOf("账单日期:");

        if (timeIndex == -1) {
            return null;
        }

        timeIndex = timeIndex + "账单日期:".length();

        int timeEndIndex = pageText.indexOf("温馨提示");

        return pageText.substring(timeIndex, timeEndIndex).trim();
    }

    /**
     * 获取错误的回执单流水号
     *
     * @param pageText 回执单文本
     * @return 流水号
     */
    private String getOrderNO(String pageText) {

        int NOIndex = pageText.indexOf("关联正向交易账务流水号：");
        NOIndex = NOIndex + "关联正向交易账务流水号：".length();

        int NOEndIndex = pageText.indexOf("温馨提示");

        return pageText.substring(NOIndex, NOEndIndex).trim();
    }

    /**
     * 获取错误的回执单户名
     *
     * @param pageText 回执单文本
     * @param isError  是否是错误类型
     * @return 户名
     */
    private String getErrorAccountName(String pageText, boolean isError) {

        if (isError) {
            int nameIndex = pageText.indexOf("户名");
            nameIndex = nameIndex + "户名".length();

            int nameEndIndex = pageText.indexOf("收");

            return pageText.substring(nameIndex, nameEndIndex).trim();
        } else {
            int nameIndex = pageText.lastIndexOf("户名");
            nameIndex = nameIndex + "户名".length();

            int nameEndIndex = pageText.indexOf("账号");

            return pageText.substring(nameIndex, nameEndIndex).trim();
        }
    }


    /**
     * 获取错误的回执单账号
     *
     * @param pageText 回执单文本
     * @param isError  是否是错误类型
     * @return 账号
     */
    private String getErrorAccountNumber(String pageText, boolean isError) {

        // 错误的回执单和正确的回执单截取的位置不同
        if (isError) {
            int accountNumberIndex = pageText.indexOf("账号");
            accountNumberIndex = accountNumberIndex + "账号".length();

            int accountNumberEndIndex = pageText.lastIndexOf("账号");

            return pageText.substring(accountNumberIndex, accountNumberEndIndex).trim();
        } else {
            int accountNumberIndex = pageText.lastIndexOf("账号");
            accountNumberIndex = accountNumberIndex + "账号".length();

            int accountNumberEndIndex = pageText.indexOf("机构");

            return pageText.substring(accountNumberIndex, accountNumberEndIndex).trim();
        }
    }

    /**
     * 获取回执单中的金额
     *
     * @param pageText 回执单文本
     * @return 金额
     */
    private String getMoney(String pageText) {
        int rmbIndex = pageText.indexOf("人民币");
        rmbIndex = rmbIndex + "人民币".length();
        int payTimeIndex = pageText.indexOf("交易时间");

        return pageText.substring(rmbIndex, payTimeIndex).trim();
    }

    /**
     * 检查给定的页面文本是否包含错误信息的字样
     *
     * @param pageText 要检查的页面文本
     * @return 如果页面文本包含"关联正向交易账务流水号"，则返回true；否则返回false
     */
    private static boolean containsErrorInfo(String pageText) {
        return pageText.contains("关联正向交易账务流水号");
    }

    public boolean isPdf(MultipartFile file) {
        // Check file extension
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".pdf")) {
            System.out.println("文件不是PDF格式，扩展名不符合要求");
            return false;
        }

//        // Optionally, check file header for added security
//        try {
//            byte[] headerBytes = new byte[4];
//            try (InputStream is = file.getInputStream()) {
//                is.read(headerBytes, 0, headerBytes.length);
//            }
//            String header = new String(headerBytes);
//            if (!header.equals("%PDF-")) {
//                System.out.println("文件不是PDF格式，文件头不符合要求");
//                return false;
//            }
//        } catch (IOException e) {
//            System.out.println("读取文件头时发生错误：" + e.getMessage());
//            return false;
//        }

        return true;
    }


}