package com.ruoyi.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ArrayListMultimap;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.codec.Base64;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PdfBaseWriter;
import com.ruoyi.domain.Book;
import com.ruoyi.domain.vo.PdfTestVO;
import com.ruoyi.service.BookService;
import com.ruoyi.mapper.BookMapper;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.List;
import java.util.stream.IntStream;

/**
* @author wangfei
* @description 针对表【t_book(书籍)】的数据库操作Service实现
* @createDate 2023-12-05 14:50:11
*/
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService{

    @Autowired
    private BookMapper bookMapper;

    @Trace
    @Tags({@Tag(key = "param", value = "arg[0]"), @Tag(key = "result", value = "returnedObj")})
    @Override
    public List<Book> selectBookList(String name) {
        return bookMapper.selectBookList(name);
    }

    @Override
    public List<Book> selectBookListException(String name) {
        if(1 == 1) {
            throw new ServiceException("测试异常处理");
        }
        return null;
    }

    @Override
    public Document generateItextPdfDocument(OutputStream os) throws Exception {

        // 创建一个A4大小的PDF
        PdfBaseWriter document = new PdfBaseWriter(os);

        // 打开
        document.open();

        // PDF文档属性
        document.addTitle("标题(测试基本PDF导出)");
        document.addAuthor("作者");
        document.addSubject("主题(基本PDF导出)");
        document.addKeywords("关键字(基本PDF导出)");
        document.addCreator("谁创建的(xxx有限公司)");
        document.addCreationDate();

        // 测试标题加文本内容
        // 添加第一个标题
        Chapter chapterOne = document.setTitle1("模拟标题1", 1);
        // 添加第一个标题下的第一个二级标题
        document.setTitle2(chapterOne, "标题1-1");
        // 添加内容
        document.writeText("石油是指气态、液态和固态的烃类混合物,具有天然的产状。石油又分为原油、天然气、天然气液及天然焦油等形式,但习惯上仍将“石油”作为“原油”的定义用。");
        // 添加第一个标题下的第二个二级标题
        document.setTitle2(chapterOne, "标题1-2");
        document.writeText("石油是一种黏稠的、深褐色液体,被称为“工业的血液”。地壳上层部分地区有石油储存。主要成分是各种烷烃、环烷烃、芳香烃的混合物。是地质勘探的主要对象之一。");
        // 添加第二个标题
        Chapter chapterTwo = document.setTitle1("模拟标题2", 2);
        document.setTitle2(chapterTwo, "标题2-1");
        document.writeText("石油的成油机理有生物沉积变油和石化油两种学说,前者较广为接受,认为石油是古代海洋或湖泊中的生物经过漫长的演化形成,属于生物沉积变油,不可再生;后者认为石油是由地壳内本身的碳生成,与生物无关,可再生。石油主要被用来作为燃油和汽油,也是许多化学工业产品,如溶液、化肥、杀虫剂和塑料等的原料。");
        document.setTitle2(chapterTwo, "标题2-2");
        document.writeText("2023年2月16日,中国石油和化学工业联合会发布数据称,中国炼油产能已超过美国,成为世界第一炼油大国。2023年2月16日,中国石油和化学工业联合会发布数据称,中国炼油产能已超过美国,成为世界第一炼油大国。");

        // 测试自定义段(可当标题、正文使用)
        document.add(document.getParagraph(1, "Paragraph"));

        // 测试自定义段方向
        Paragraph paragraph = document.getParagraph(2, "左对齐");
        paragraph.setAlignment(Element.ALIGN_RIGHT);
        document.add(paragraph);

        // 测试(List)列
        List<String> list = new ArrayList<>();
        list.add("第一行");
        list.add("第二行");
        list.add("第三行");
        document.writeList(list, true);

        // 测试(Map)列
        Map<String, String> map = new HashMap<>();
        map.put("甲方", "可填入动态公司");
        map.put("乙方", "可填入动态公司");
        map.put("时间", String.valueOf(DateUtil.date()));
        map.put("地点", "可填入动态地点");
        document.writeList(map, false);

        // 测试带表头的表格
        ArrayList<LinkedHashMap<String, Object>> rows = new ArrayList<>();
        for (int i = 0;i < 10;i ++) {
            LinkedHashMap<String, Object> row = new LinkedHashMap<>();
            row.put("姓名", "张三"+i);
            row.put("年龄", 23 + i);
            row.put("成绩", 88.32 + i);
            row.put("是否合格", true);
            row.put("考试日期", DateUtil.date());
            rows.add(row);
        }
        document.writeTable(rows);

        // 测试自定义表格
        PdfPTable table = new PdfPTable(new float[]{40, 150});
        table.setWidthPercentage(100);
        // 上下边距
        table.setSpacingBefore(10);
        table.setSpacingAfter(10);
        document.writeCell("电话:",1, 1, table);
        document.writeCell("地址:", 1, 1, table);
        document.writeCell("手机号:", 1, 1, table);
        // 一个cell图文混合
        List<String> list2 = new ArrayList<>();
        list2.add("哈哈哈");
        list2.add("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
        list2.add("啊啊啊");
        list2.add( "C:/Users/gxk/Pictures/Saved Pictures/123.jpg");
        document.writeTextAndImageCell(list2, table);
        // 把表格添加进入PDF
        document.add(table);

        // 图片
        Image image = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
        image.setAlignment(Element.ALIGN_CENTER);
        // 缩放
        image.scalePercent(60);
        document.add(image);

        // 关闭
        document.close();
        return document;
    }

    /**
     * 测试生成PDF - API方式渲染动态表格
     * @param os
     * @return
     * @throws Exception
     */
    @Override
    public Document testGeneratePDF(OutputStream os) throws Exception {

        // 动态数据
        List<PdfTestVO> pdfTestVOS = dynamicTabularData();

        // 创建PDF
        PdfBaseWriter document = new PdfBaseWriter(os);
        // 打开
        document.open();
        // 添加内容
        document.add(document.getParagraph(1, "xxx调查表"));
        Chapter title1 = document.setTitle1("动态测试表格", 1);
        // 动态表格
        addTable(pdfTestVOS, document, title1);

        // 关闭
        document.close();
        return document;
    }

    private void addTable(List<PdfTestVO> pdfTestVOS, PdfBaseWriter document, Chapter chapter) {
        IntStream.range(0, pdfTestVOS.size()).forEach(index -> {
            PdfTestVO pdfTestVO = pdfTestVOS.get(index);
            try {
                document.setTitle2(chapter, pdfTestVO.getTestItem());
                // 生成表格
                PdfPTable table = new PdfPTable(new float[]{40, 150});
                table.setTotalWidth(500);
                table.setLockedWidth(true);
                table.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.getDefaultCell().setBorder(1);
                // 添加行
                table.addCell(document.createCenterCell("测试编号"));
                table.addCell(document.createLeftCell(pdfTestVO.getTestNumber()));
                table.addCell(document.createCenterCell("样本编号"));
                table.addCell(document.createLeftCell(pdfTestVO.getSampleNumber()));
                table.addCell(document.createCenterCell("检测项目"));
                table.addCell(document.createLeftCell(pdfTestVO.getTestItem()));
                table.addCell(document.createCenterCell("风险等级"));
                table.addCell(document.createLeftCell(pdfTestVO.getRiskLevel()));
                table.addCell(document.createCenterCell("测试方法"));
                table.addCell(document.createLeftCell(pdfTestVO.getTestMethod()));
                table.addCell(document.createCenterCell("测试结果"));
                table.addCell(document.createLeftCell(pdfTestVO.getTestResult()));
                table.addCell(document.createCenterCell("漏洞危害"));
                table.addCell(document.createLeftCell(pdfTestVO.getVulnerabilityHazard()));
                table.addCell(document.createCenterCell("测试详情"));

                PdfPCell cell = new PdfPCell();
                cell.addElement(document.createTextInImageCell(pdfTestVO.getTestDetails()));
                Image img = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
                img.scaleToFit(100, 100);
                cell.addElement(img);
                cell.addElement(document.createTextInImageCell("车辆采用白名单策略,需客户端设置IP地址为192.168.69.71/24才可以与之通信,车辆IP地址为192.168.69.8。"));
                Image imgTwo = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/123.jpg");
                img.scaleToFit(100, 100);
                cell.addElement(imgTwo);
                cell.addElement(document.createTextInImageCell("请依次完成以下操作:\n\n1)使用电动螺丝刀拆开车机外壳,注意不要造成物理性破坏;\n\n2)肉眼观察板子上是否有明显的JTAG调试接口,需要注意CPU附近的点和引脚的各种信息;\n\n注:JTAG通常主要由以下4个针脚组成:\n\n①TCK ... Test Clock\n\n②TMS ... Test Mode Select \n\n③TDI ... Test Data In\n\n④TDO ... Test Data Out\n\n3)通过五倍光学放大镜仔细查看PCB板上的信息,找到带有JTAG、TCK、TMS、TDI、TDO等相关的信息的点位,比如下图:\n\nhttp://10.12.48.80:8089/file_server/api_v1/downloadSysFile?key=e45566a4ebf14eb299d60b180473f9c84c&ts=2024_03_05&token=7f5ac770a013f7ce74205992257f5d9b&tmp=false&inline=true\n\n4)将测试过程中的 PCB 板照片等作为测试证明材料上传至平台。\n\n<br>\n\n**请根据PCB板上是否存在明显的JTAG调试接口对节点结果进行判断。**)"));
                Image imgThird = Image.getInstance("http://49.232.167.247:22038/vehicle-quality-review-oss/2023/12/19/1702891760057_20231219095525A001.jpg");
                img.scaleToFit(100, 100);
                cell.addElement(imgThird);
                table.addCell(cell);
                table.addCell(document.createCenterCell("修复建议"));
                table.addCell(document.createLeftCell(pdfTestVO.getRepairSuggestion()));
                document.add(table);
            } catch (DocumentException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 生成测试数据
     * @return
     */
    private List<PdfTestVO> dynamicTabularData() {
        List<PdfTestVO> dataList = new ArrayList<>();
        PdfTestVO dos = PdfTestVO.builder()
                .testNumber("EH3-Vehicle-PT-001")
                .sampleNumber("LNNAJDDU4PD490747")
                .testItem("DOS攻击")
                .riskLevel("无风险")
                .testMethod("1.使用奇瑞设备接入整车OBD口; \n" +
                        "2.使用电脑连接OBD口; \n" +
                        "3.使用电脑打开OBD软件; \n" +
                        "4.点击软件中的“诊断”按钮;")
                .testResult("对车辆以太网DOS攻击后,车辆无异常,车辆以太网服务未受到影响,测试通过。")
                .vulnerabilityHazard("拒绝车辆正常的服务访问,影响车辆的正常运行")
                .testDetails("1.使用奇瑞设备接入整车OBD口;")
                .repairSuggestion("无").build();
        dataList.add(dos);
        PdfTestVO blur = PdfTestVO.builder()
                .testNumber("EH3-Vehicle-PT-002")
                .sampleNumber("LNNAJDDU4PD490747")
                .testItem("模糊测试")
                .riskLevel("无风险")
                .testMethod("1.使用奇瑞设备接入整车OBD口;\n" +
                        "2.对Doip协议进行模糊测试,尝试影响以太网诊断的可用性,若车辆未出现异常则测试通过,否则不通过。")
                .testResult("车辆模糊过程中无异常,未发现未知漏洞,测试通过。")
                .vulnerabilityHazard("模糊测试可能导致车辆异常。")
                .testDetails("1.使用奇瑞设备接入整车OBD口;")
                .repairSuggestion("无").build();
        dataList.add(blur);
        return dataList;
    }



    @Override
    public void generateTempPDF(HttpServletResponse response) throws Exception {
//        PdfReader reader = null;
//        PdfStamper ps = null;
//        OutputStream fos = null;
//        ByteArrayOutputStream bos = null;
//        Base64.InputStream fin = null;
//        ServletOutputStream out = null;
//        try {
//            // 模板绝对路径--服务器
//            String fileName = "/template/receipt_template.pdf";
//            // 读取现有模板内容
//            reader = new PdfReader(fileName);
//            // 创建输出流
//            bos = new ByteArrayOutputStream();
//            // 实例化PdfStamper准备编辑pdf内容
//            ps = new PdfStamper(reader, bos);
//
//            // 获取表单所有元素
//            AcroFields fields = ps.getAcroFields();
//
//            // 设置具体字体格式的编码, 不设置的话中文可能不会显示
//            BaseFont bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//            fields.addSubstitutionFont(bf);
//
//            // 动态添加所需要的数据,key跟模板中对应文本域名称一致
//            Map<String, String> map = new HashMap<>();
//            map.put("code", "1234567890fjdksjfdsfdsffdsjfdssssssttttttttttttttt");
//            map.put("table_image", "C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
//
//            // 渲染
//            fillData(fields, map, ps);
//
//            //必须要调用这个,否则文档不会生成的
//            ps.setFormFlattening(true);
//            if(ps != null){
//                ps.close();
//            }
//            //生成pdf路径存放的路径
//            fos = response.getOutputStream();
//            fos.write(bos.toByteArray());
//
//        }catch (Exception e){
//            e.printStackTrace();
//        }finally {
//            if(fos!=null){
//                fos.flush();
//                fos.close();
//            }
//            if (bos != null){
//                bos.close();
//            }
//            if(reader != null){
//                reader.close();
//            }
//        }
    }

    /**
     * 填充模板中的数据
     * @param fields
     * @param data 是一个Map<String,String> 主要存储 key 表单模板中的单元格名 value为想要赋的值,遍历
     * @param ps
     */
    public void fillData(AcroFields fields, Map<String, String> data, PdfStamper ps) {
//        try {
//            for (String key : data.keySet()) {
//                String value = data.get(key);
//                if (key.contains("image")) {
//                    addImageToPdf(key, fields, ps, value);
//                    continue;
//                }
//                // 为字段赋值,注意字段名称是区分大小写的
//                fields.setField(key, value);
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 添加图片
     * @param key 应为模板名
     * @param form 动态字段
     * @param stamper
     * @param filePath 本地图片路径
     * @throws DocumentException
     * @throws IOException
     * @throws IOException
     */
    private static void addImageToPdf(String key,AcroFields form, PdfStamper stamper, String filePath) throws DocumentException, IOException, IOException {

//        // 通过图片域名获取所在页和坐标,左下角为起点
//        int pageNo = form.getFieldPositions(key).get(0).page;
//        Rectangle signRect = form.getFieldPositions(key).get(0).position;
//        float x = signRect.getLeft();
//        float y = signRect.getBottom();
//
//        // 读图片
//        Image image = Image.getInstance(filePath);
//        // 获取操作的页面
//        PdfContentByte under = stamper.getOverContent(pageNo);
//        // 根据域的大小缩放图片
//        image.scaleToFit(signRect.getWidth() * 2, signRect.getHeight());
//        // 添加图片并设置位置(个人通过此设置使得图片垂直水平居中,可参考,具体情况已实际为准)
//        image.setAbsolutePosition(x, y);
//        under.addImage(image);
    }
}