package handler

import (
	webServerEntity "cicv-data-closedloop/amd64/web_server/entity"
	"cicv-data-closedloop/amd64/web_server/infra"
	"cicv-data-closedloop/common/config/c_db"
	"cicv-data-closedloop/common/config/c_log"
	commonEntity "cicv-data-closedloop/common/entity"
	"cicv-data-closedloop/common/util"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/signintech/gopdf"
	"io"
	"log"
	"math"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

var (
	defaultTime            = time.Date(2006, time.January, 2, 15, 4, 5, 0, time.Local)
	cacheMutex             sync.Mutex
	cacheTeamName          = make(map[string]time.Time)
	heartBeatTimeThreshold = 5 * time.Second // 心跳时间
	InitialPositionX       = 456292.00       // todo 需要比赛确认起点
	InitialPositionY       = 4397957.00      // todo 需要比赛确认起点
	trialBegin             = time.Date(2024, time.June, 16, 13, 00, 00, 0, time.Local)
	trialEnd               = time.Date(2024, time.June, 19, 23, 59, 59, 0, time.Local)
)

// 考试心跳
func Tick(c *gin.Context) {
	param := new(webServerEntity.ExamPao)
	// 映射到结构体
	if err := c.ShouldBindJSON(&param); err != nil {
		c_log.GlobalLogger.Error("请求体解析失败，错误信息为：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "请求体解析失败。",
		})
		return
	}
	teamName := param.TeamName
	positionX, _ := strconv.ParseFloat(param.PositionX, 64)
	var positionY float64
	numStr := param.PositionY
	_, _ = fmt.Sscanf(numStr, "%e", &positionY)
	if !util.ContainsKey(cacheTeamName, teamName) && math.Abs(positionX-InitialPositionX) < 5.00 && math.Abs(positionY-InitialPositionY) < 5.00 { // （在起点开始）
		sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-insert-begin_time-and-topic-by-team_name.sql"])

		stage := ""
		if time.Now().Before(trialBegin) {
			stage = "表演赛"
		} else if time.Now().After(trialBegin) && time.Now().Before(trialEnd) {
			stage = "预赛"
		} else {
			stage = "决赛"
		}
		competitionBegin := time.Now()
		cacheTeamName[teamName] = competitionBegin
		c_log.GlobalLogger.Infof("当前比赛阶段为 %v ,队伍 %v 在起始点范围内第一次启动，保存新一条比赛记录的开始时间 %v", stage, teamName, competitionBegin)
		if err := c_db.DoTx(sqlTemplate, []any{param.TeamName, stage, competitionBegin}); err != nil {
			c_log.GlobalLogger.Error("保存比赛开始时间报错：", err)
			c.JSON(http.StatusBadRequest, commonEntity.Response{Code: 500, Msg: "保存比赛开始时间报错。"})
			return
		}
	} else if !util.ContainsKey(cacheTeamName, teamName) && (math.Abs(positionX-InitialPositionX) > 5.00 || math.Abs(positionY-InitialPositionY) > 5.00) { // 不在起点（开始）
		// 车辆不是在起点启动的自动驾驶模式
		selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
		if err != nil {
			c_log.GlobalLogger.Error("读取sql文件报错：", err)
			return
		}
		// 可以传参数
		var result []webServerEntity.ExamPo
		if err = c_db.MysqlDb.Select(&result, selectSql, teamName); err != nil {
			c_log.GlobalLogger.Error("数据库查询报错：", err)
			return
		}
		if len(result) == 1 {
			c_log.GlobalLogger.Info("上一条数据记录为：", result[0])
		}
		// 添加队伍名到缓存中
		cacheTeamName[teamName] = time.Now()
		// 更新记录结束时间为默认时间
		sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-team_name.sql"])
		if err = c_db.DoTx(sqlTemplate, []any{
			defaultTime,
			teamName,
		}); err != nil {
			c_log.GlobalLogger.Error("插入数据报错：", err)
			return
		}
		c_log.GlobalLogger.Infof("队伍 %v 的考试在中途中断后重新开始。", teamName)
	} else if util.ContainsKey(cacheTeamName, teamName) { // 进行中
		cacheTeamName[teamName] = time.Now()
		c_log.GlobalLogger.Errorf("接收到心跳信息，队伍名字为 %s，x坐标为  %.f，y坐标为 %.f ", teamName, positionX, positionY)
	} else {
		c_log.GlobalLogger.Errorf("接收到心跳信息但考试并未开始，队伍名字为 %s，x坐标为  %.f，y坐标为 %.f ", teamName, positionX, positionY)
	}

	c.JSON(http.StatusOK, commonEntity.Response{
		Code: 200,
		Msg:  "心跳接收成功。",
	})
}

func ExamEndTicker() {
	// 创建一个定时器，每隔一秒触发一次
	ticker := time.NewTicker(1 * time.Second)
	for {
		select {
		// 定时器触发时执行的代码
		case <-ticker.C:
			cacheMutex.Lock()
			{
				var keysToDelete []string
				for teamName, heartBeatTime := range cacheTeamName {
					if time.Since(heartBeatTime) > heartBeatTimeThreshold { // 检查缓存中的队名，如果超过心跳时间，则代表考试结束，删除缓存中的队名
						c_log.GlobalLogger.Infof("队伍 %v 心跳超时，比赛结束。", teamName)

						keysToDelete = append(keysToDelete, teamName)
					}
				}
				for _, teamName := range keysToDelete { // 检查缓存中的队名，如果超过心跳时间，则代表考试结束，删除缓存中的队名
					delete(cacheTeamName, teamName)
					// 1 查询指定队伍的开始时间最新的考试是否有结束时间，如果有则不在处理，如果没有则更新
					var result []webServerEntity.ExamPo
					selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
					if err != nil {
						c_log.GlobalLogger.Error("读取sql文件报错：", err)
						return
					}
					// 可以传参数
					if err = c_db.MysqlDb.Select(&result, selectSql, teamName); err != nil {
						c_log.GlobalLogger.Error("数据库查询报错：", err)
						return
					}
					if !result[0].EndTime.Equal(defaultTime) {
						c_log.GlobalLogger.Error("赛队", teamName, "考试已结束！")
						return
					}
					// 更新到数据库（只更新最新一条）
					stage := ""
					if time.Now().Before(trialBegin) {
						stage = "表演赛"
					} else if time.Now().After(trialBegin) && time.Now().Before(trialEnd) {
						stage = "预赛"
					} else {
						stage = "决赛"
					}
					// 查询最新一条的id
					selectSql, err = util.ReadFile(c_db.SqlFilesMap["exam-select-max-id-by-team_name-and-topic.sql"])
					if err != nil {
						c_log.GlobalLogger.Error("读取sql文件报错：", err)
						return
					}
					// 可以传参数
					var resultId []int
					if err = c_db.MysqlDb.Select(&resultId, selectSql, teamName, stage); err != nil {
						c_log.GlobalLogger.Error("数据库查询报错：", err)
						return
					}
					if len(resultId) == 1 {
						c_log.GlobalLogger.Info("更新数据结束时间，id为：", resultId)

						sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-id.sql"])
						if err := c_db.DoTx(sqlTemplate, []any{
							time.Now(),
							resultId[0],
						}); err != nil {
							c_log.GlobalLogger.Error("插入数据报错：", err)
							return
						}
					} else {
						c_log.GlobalLogger.Error("查询id失败：", resultId)
					}
					c_log.GlobalLogger.Infof("队伍 %v 的考试结束。", teamName)

				}
			}
			cacheMutex.Unlock()
		}
	}
}

// 考试开始时间
func Begin(c *gin.Context) {
	param := new(webServerEntity.ExamPao)
	// 映射到结构体
	if err := c.ShouldBindJSON(&param); err != nil {
		c_log.GlobalLogger.Error("项目启动接收请求参数报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "请求体解析失败。",
		})
		return
	}
	// 插入到数据库
	sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-insert-begin_time-by-team_name.sql"])
	c_log.GlobalLogger.Info("插入比赛开始时间", sqlTemplate)
	if err := c_db.DoTx(sqlTemplate, []any{
		param.TeamName,
		time.Now(),
	}); err != nil {
		c_log.GlobalLogger.Error("插入数据报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "插入数据报错。",
		})
		return
	}
	c.JSON(http.StatusOK, commonEntity.Response{
		Code: 200,
		Msg:  "插入数据成功。",
	})
}

// 考试结束时间
func End(c *gin.Context) {
	param := new(webServerEntity.ExamPao)
	// 映射到结构体
	if err := c.ShouldBindJSON(&param); err != nil {
		c_log.GlobalLogger.Error("项目启动接收请求参数报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "请求体解析失败。",
		})
		return
	}
	// 1 查询指定队伍的开始时间最新的考试是否有结束时间，如果有则不在处理，如果没有则更新
	var result []webServerEntity.ExamPo
	selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
	if err != nil {
		c_log.GlobalLogger.Error("读取sql文件报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "读取sql文件报错。",
		})
		return
	}
	// 可以传参数
	if err = c_db.MysqlDb.Select(&result, selectSql, param.TeamName); err != nil {
		c_log.GlobalLogger.Error("数据库查询报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "数据库查询报错。",
		})
		return
	}
	c_log.GlobalLogger.Info("数据库查询成功：", result)
	if !result[0].EndTime.Equal(defaultTime) {
		c_log.GlobalLogger.Error("赛队", param.TeamName, "重复请求考试结束接口！")
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "重复请求。",
		})
		return
	}
	// 更新到数据库
	sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-team_name.sql"])
	if err := c_db.DoTx(sqlTemplate, []any{
		time.Now(),
		param.TeamName,
	}); err != nil {
		c_log.GlobalLogger.Error("插入数据报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "插入数据报错。",
		})
		return
	}
	c.JSON(http.StatusOK, commonEntity.Response{
		Code: 200,
		Msg:  "插入数据成功。",
	})
}

// 分页查询
// 如果日期为默认值，则返回空""
func Page(c *gin.Context) {
	param := new(webServerEntity.ExamPagePao)
	_ = c.ShouldBindJSON(&param)
	var resultPos []webServerEntity.ExamPo
	var resultPosTotal []int
	var pageSql string
	var totalSql string
	offset := (param.CurrentPage - 1) * param.PageSize
	size := param.PageSize
	if param.TeamName == "" && param.Topic == "" {
		pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page.sql"])
		totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total.sql"])
		err := c_db.MysqlDb.Select(&resultPos, pageSql, offset, size)
		if err != nil {
			c_log.GlobalLogger.Error(err)
		}
		err = c_db.MysqlDb.Select(&resultPosTotal, totalSql)
		if err != nil {
			c_log.GlobalLogger.Error(err)
		}
	}
	if param.TeamName != "" && param.Topic == "" {
		pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-team_name.sql"])
		totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-team_name.sql"])
		_ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.TeamName+"%", offset, size)
		_ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.TeamName+"%")
	}
	if param.TeamName == "" && param.Topic != "" {
		pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-topic.sql"])
		totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-topic.sql"])
		_ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.Topic+"%", offset, size)
		_ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.Topic+"%")
	}
	if param.TeamName != "" && param.Topic != "" {
		pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-team_name-and-topic.sql"])
		totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-team_name-and-topic.sql"])
		_ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.TeamName+"%", "%"+param.Topic+"%", offset, size)
		_ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.TeamName+"%", "%"+param.Topic+"%")
	}
	var resultVos []webServerEntity.ExamVo
	for _, po := range resultPos {

		resultVos = append(resultVos, webServerEntity.ExamVo{
			Id:              po.Id,
			TeamName:        po.TeamName,
			Topic:           po.Topic,
			BeginTime:       util.GetTimeString(po.BeginTime),
			EndTime:         util.GetTimeString(po.EndTime),
			ScoreOnline:     po.ScoreOnline,
			ScoreOffline:    po.ScoreOffline,
			ScoreFinal:      po.ScoreFinal,
			Details:         po.Details,
			ScoreReportPath: po.ScoreReportPath,
		})
	}

	c.JSON(http.StatusOK, commonEntity.Response{
		Code:  200,
		Msg:   "分页查询成功！",
		Data:  resultVos,
		Total: resultPosTotal[0],
	})
}

// 评分报告pdf下载
func Report(c *gin.Context) {
	param := new(webServerEntity.ExamReportPao)
	// 映射到结构体
	if err := c.ShouldBindJSON(&param); err != nil {
		c_log.GlobalLogger.Error("接收请求参数报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "请求体解析失败。",
		})
		return
	}
	// 查询打分详情
	var detailsResult []string
	selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-details-by-id.sql"])
	if err != nil {
		c_log.GlobalLogger.Error("读取sql文件报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "读取sql文件报错。",
		})
		return
	}
	// 可以传参数
	if err = c_db.MysqlDb.Select(&detailsResult, selectSql, param.Id); err != nil {
		c_log.GlobalLogger.Error("数据库查询报错：", err)
		c.JSON(http.StatusBadRequest, commonEntity.Response{
			Code: 500,
			Msg:  "数据库查询报错。",
		})
		return
	}
	details := detailsResult[0]
	// 解析详情为数组
	var detailsDtos []webServerEntity.DetailsDto
	_ = json.Unmarshal([]byte(details), &detailsDtos)

	layout := "2006-01-02 15:04:05"
	beginTime, _ := time.Parse(layout, param.BeginTime)
	endTime, _ := time.Parse(layout, param.EndTime)
	// 1 根据ID查询数据
	// 2 根据数据生成pdf
	// 3 创建pdf文件
	{
		// 初始化 pdf 对象
		pdf := gopdf.GoPdf{}
		pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
		// 添加字体文件到pdf
		err := pdf.AddTTFFont("simfang", infra.ApplicationYaml.Pdf.Ttf)
		if err != nil {
			log.Print(err.Error())
			return
		}

		leftMargin := 70.0
		topMargin := 100.0
		lineHeight := 25.0
		tableWidth := 450.0
		pdf.SetLeftMargin(leftMargin) // 设置左边距
		alignOptionText := gopdf.CellOption{Align: gopdf.Left | gopdf.Middle}
		//alignOptionText2 := gopdf.CellOption{Align: gopdf.Center | gopdf.Middle}
		alignOptionTable := gopdf.CellOption{Align: gopdf.Center | gopdf.Middle, Border: gopdf.Left | gopdf.Right | gopdf.Bottom | gopdf.Top}
		alignOptionTable2 := gopdf.CellOption{Align: gopdf.Left | gopdf.Middle}

		// ------- 封面页 -------
		pdf.AddPage()
		{
			err = pdf.SetFont("simfang", "", 36)
			err = pdf.Image(infra.ApplicationYaml.Pdf.BackgroundPng, 0, 0, nil) // 背景图片
			err = pdf.Image(infra.ApplicationYaml.Pdf.LogoPng, 20, 20, &gopdf.Rect{W: 320, H: 100})
			{
				pdf.SetXY(100, 250)
				_ = pdf.Text("车路云一体化算法挑战赛")
			}
			{
				pdf.SetXY(220, 315) // 200
				_ = pdf.Text("评分报告")
			}
			_ = pdf.SetFont("simfang", "", 14)
			currentLine := 0.0
			tableCellWidth := 100.0
			tableLeftMartin := 190.0
			tableTopMartin := 500.0
			{
				{
					pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "赛队编号：", alignOptionTable2)
				}
				{
					pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, param.TeamName, alignOptionTable2)
				}
				currentLine++
			}
			{
				{
					pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "评测车型：", alignOptionTable2)
				}
				{
					pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "多功能车平台", alignOptionTable2)
				}
				currentLine++
			}
			{
				{
					pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "评测地点：", alignOptionTable2)
				}
				{
					pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "天津生态城", alignOptionTable2)
				}
				currentLine++
			}
			{
				{
					pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "报告时间：", alignOptionTable2)
				}
				{
					pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, time.Now().Format("2006年01月02日"), alignOptionTable2)
				}
				currentLine++
			}
			{
				pdf.SetXY(165, 775)
				_ = pdf.Cell(nil, "国汽（北京）智能网联汽车研究院有限公司")
			}
		}
		// todo 先不要目录页
		//// ------- 目录页 -------
		//{
		//	pdf.AddPage()
		//	currentLine := 0.0
		//	{
		//		err = pdf.SetFont("simfang", "", 18)
		//		pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
		//		_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "目录", alignOptionText2)
		//		currentLine++
		//		currentLine++
		//	}
		//	{
		//		err = pdf.SetFont("simfang", "", 14)
		//		pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
		//		currentLine++
		//		_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "1. 总体情况 ............................... 1", alignOptionText)
		//	}
		//}
		// ------- 详情页 第一页 -------
		{
			pdf.AddPage()
			currentLine := 0.0
			// 1. 总体分数情况
			{
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "1. 总体分数情况", alignOptionText)
					currentLine++
				}
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "整体得分："+util.ToString(param.ScoreFinal), alignOptionText)
					currentLine++
				}
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "线上得分："+util.ToString(param.ScoreFinal), alignOptionText)
					currentLine++
				}
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "线下得分：", alignOptionText)
					currentLine++
				}
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "整体耗时："+endTime.Sub(beginTime).String(), alignOptionText)
					currentLine++
				}
			}
			// 2. 分数详情
			{
				//columnNumber := 4.0                         // 列数
				//tableCellWidth := tableWidth / columnNumber // 单元格宽度
				tableCellWidth1 := 50.0
				tableCellWidth2 := 300.0
				tableCellWidth3 := 70.0
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "2. 分数详情", alignOptionText)
					currentLine++
				}
				// 分数详情表格
				{
					{
						pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
						_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth1, H: lineHeight}, "序号", alignOptionTable)
					}
					{
						pdf.SetXY(leftMargin+tableCellWidth1, topMargin+currentLine*lineHeight)
						_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth2, H: lineHeight}, "场景名称", alignOptionTable)
					}
					{
						pdf.SetXY(leftMargin+tableCellWidth1+tableCellWidth2, topMargin+currentLine*lineHeight)
						_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth3, H: lineHeight}, "线上得分", alignOptionTable)
					}
					currentLine++
				}
				for i := 0; i < len(detailsDtos); i++ {
					{
						{
							pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
							_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth1, H: lineHeight}, util.ToString(i+1), alignOptionTable)
						}
						{
							pdf.SetXY(leftMargin+tableCellWidth1, topMargin+currentLine*lineHeight)
							_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth2, H: lineHeight}, detailsDtos[i].SceneName, alignOptionTable)
						}
						{
							pdf.SetXY(leftMargin+tableCellWidth1+tableCellWidth2, topMargin+currentLine*lineHeight)
							_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth3, H: lineHeight}, util.ToString(detailsDtos[i].TotalScore+detailsDtos[i].DeductedScore), alignOptionTable)
						}
						currentLine++
					}
				}

			}
		}
		// ------- 详情页 第二页 -------
		var detailsDtos2 []webServerEntity.DetailsDto // 扣分的场景
		for _, detailsDto := range detailsDtos {
			if detailsDto.Reason != "" {
				detailsDtos2 = append(detailsDtos2, detailsDto)
			}
		}
		size := len(detailsDtos2)
		{
			pdf.AddPage()
			currentLine := 0.0
			// 3. 线上扣分详情
			{
				//columnNumber := 3.0                         // 列数
				//tableCellWidth := tableWidth / columnNumber // 单元格宽度
				tableCellWidth := 450.0 // 单元格宽度
				{
					pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
					_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "3. 线上扣分详情", alignOptionText)
					currentLine++
				}
				for i := 0; i < 8; i++ {
					// 场景1
					{
						{
							pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
							_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "（"+util.ToString(i+1)+"）"+detailsDtos2[i].SceneName, alignOptionText)
							currentLine++
						}
						// 场景1 表格
						{
							//{
							//	pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
							//	_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "序号", alignOptionTable)
							//}
							//{
							//	pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
							//	_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分点", alignOptionTable)
							//}
							{
								pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
								_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分说明", alignOptionTable)
							}
							currentLine++
						}
						//for j := 0; j < 1; j++ {
						{
							//{
							//	pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
							//	_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, util.ToString(j+1), alignOptionTable)
							//}
							//{
							//	pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
							//	_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
							//}
							{
								pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
								_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, detailsDtos2[i].Reason, alignOptionTable)
							}
							currentLine++
						}
						//}
					}
				}
			}
			//if size <= 8 {
			//	// 4 作品优化建议
			//	{
			//		pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
			//		_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "4. 作品优化建议", alignOptionText)
			//		currentLine++
			//	}
			//}
		}
		// ------- 详情页 第三页 -------

		if size > 8 {
			pdf.AddPage()
			currentLine := 0.0
			// 3. 线上扣分详情
			{
				columnNumber := 3.0                         // 列数
				tableCellWidth := tableWidth / columnNumber // 单元格宽度
				for i := 5; i < 10; i++ {
					// 场景1
					{
						{
							pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
							_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "（"+util.ToString(i+1)+"）xxxx场景", alignOptionText)
							currentLine++
						}
						// 场景1 表格
						{
							{
								pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
								_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "序号", alignOptionTable)
							}
							{
								pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
								_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分点", alignOptionTable)
							}
							{
								pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
								_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分说明", alignOptionTable)
							}
							currentLine++
						}
						for j := 0; j < 2; j++ {
							{
								{
									pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
									_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, util.ToString(j+1), alignOptionTable)
								}
								{
									pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
									_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
								}
								{
									pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
									_ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
								}
								currentLine++
							}
						}
					}
				}
			}
			//// 4 作品优化建议
			//{
			//	pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
			//	_ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "4. 作品优化建议", alignOptionText)
			//	currentLine++
			//}
		}
		//// ------- 附录页 -------
		//pdf.AddPage()
		//{
		//	pdf.SetXY(leftMargin, topMargin)
		//	_ = pdf.Text("附件：评分规则")
		//	pdf.AddExternalLink("https://www.baidu.com/", leftMargin, topMargin-lineHeight, 6*14, lineHeight)
		//}
		//// 写入本地
		//pdf.WritePdf("D:\\hello.pdf")
	}

	// 打开要发送的文件
	file, err := os.Open("D:\\hello.pdf")
	if err != nil {
		c.String(http.StatusNotFound, "文件未找到")
		return
	}
	defer file.Close()

	// 将文件复制到响应主体
	_, err = io.Copy(c.Writer, file)
	if err != nil {
		c.String(http.StatusInternalServerError, "无法复制文件到响应体")
		return
	}
}
