package bbxt

import (
	"ai_scheduler/internal/config"
	"ai_scheduler/internal/pkg/utils_oss"
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"

	"github.com/gofiber/fiber/v2/log"
	"github.com/xuri/excelize/v2"
)

type Uploader struct {
	ossClient *utils_oss.Client
	config    *config.Config
}

func NewUploader(oss *utils_oss.Client, config *config.Config) *Uploader {
	return &Uploader{
		ossClient: oss,
		config:    config,
	}
}

func (u *Uploader) Run(report *ReportRes) (err error) {
	if report == nil {
		return
	}
	if len(report.Path) == 0 {
		return
	}
	f, err := excelize.OpenFile(report.Path)
	if err != nil {
		return err
	}
	defer f.Close()

	excelBytes, err := f.WriteToBuffer()
	if err != nil {
		return fmt.Errorf("write to bytes failed: %v", err)
	}

	picBytes, err := u.excel2picPy(report.Path, excelBytes.Bytes(), 2)
	if err != nil {
		return fmt.Errorf("excel2picPy failed: %v", err)
	}
	// b.savePic("temp.png", picBytes) // 本地生成图片，仅测试
	// outputPath 提取文件名（不包含扩展名）
	filename := filepath.Base(report.Path)
	filename = strings.TrimSuffix(filename, filepath.Ext(filename))
	report.Url = u.uploadToOSS(filename, picBytes)
	log.Infof("imgUrl: %s", report.Url)

	return
}

// excel2picPy 将excel转换为图片python
// python 接口如下：
// curl --location --request POST 'http://excel2pic:8000/api/v1/convert' \
// --header 'Content-Type: multipart/form-data; boundary=--------------------------952147881043913664015069' \
// --form 'file=@"C:\\Users\\Administrator\\Downloads\\销售同比分析2025-12-29 0-12点.xlsx"' \
// --form 'sheet_name="销售同比分析"'
func (u *Uploader) excel2picPy(templatePath string, excelBytes []byte, scale int) ([]byte, error) {
	// 1. 获取 Sheet Name
	// 尝试从 excelBytes 解析，如果失败则使用默认值 "Sheet1"
	sheetName := "Sheet1"
	f, err := excelize.OpenReader(bytes.NewReader(excelBytes))
	if err == nil {
		sheetName = f.GetSheetName(0)
		if sheetName == "" {
			sheetName = "Sheet1"
		}
		f.Close()
	}

	// 2. 构造 Multipart 请求
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// 添加文件字段
	// 使用 templatePath 的文件名作为上传文件名，如果没有则用 default.xlsx
	filename := "default.xlsx"
	if templatePath != "" {
		filename = filepath.Base(templatePath)
	}

	part, err := writer.CreateFormFile("file", filename)
	if err != nil {
		return nil, fmt.Errorf("create form file failed: %v", err)
	}
	if _, err = part.Write(excelBytes); err != nil {
		return nil, fmt.Errorf("write file part failed: %v", err)
	}

	// 添加 sheet_name 字段
	if err = writer.WriteField("sheet_name", sheetName); err != nil {
		return nil, fmt.Errorf("write field sheet_name failed: %v", err)
	}

	// 添加 scale 字段
	if scale <= 0 {
		scale = 2
	}
	if err = writer.WriteField("scale", fmt.Sprintf("%d", scale)); err != nil {
		return nil, fmt.Errorf("write field scale failed: %v", err)
	}

	if err = writer.Close(); err != nil {
		return nil, fmt.Errorf("close writer failed: %v", err)
	}

	// 3. 发送 HTTP POST 请求

	req, err := http.NewRequest("POST", u.config.EinoTools.Excel2Pic.BaseURL, body)
	if err != nil {
		return nil, fmt.Errorf("create request failed: %v", err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("send request failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		respBody, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("api request failed with status: %d, body: %s", resp.StatusCode, string(respBody))
	}

	// 4. 读取响应 Body (图片内容)
	picBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response body failed: %v", err)
	}

	return picBytes, nil
}

// savePic 保存图片到本地
func (u *Uploader) savePic(outputPath string, picBytes []byte) error {
	dir := filepath.Dir(outputPath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("create directory failed: %v", err)
	}
	return os.WriteFile(outputPath, picBytes, 0644)
}

// uploadToOSS 上传至 oss 返回图片url
func (u *Uploader) uploadToOSS(fileName string, fileBytes []byte) string {
	objectKey := fmt.Sprintf("ai-scheduler/data-analytics/images/%s.png", fileName)
	url, err := u.ossClient.UploadBytes(objectKey, fileBytes)
	if err != nil {
		log.Errorf("oss upload failed: %v", err)
		return ""
	}
	return url
}

//// uploadToOSS 上传至 oss 返回图片url
//func (r *ReportRes) To(fileName string, fileBytes []byte) string {
//	objectKey := fmt.Sprintf("ai-scheduler/data-analytics/images/%s.png", fileName)
//	url, err := u.ossClient.UploadBytes(objectKey, fileBytes)
//	if err != nil {
//		log.Errorf("oss upload failed: %v", err)
//		return ""
//	}
//	return url
//}

func (b *BbxtTools) OfficialProductSumDeclineExcel(templatePath, outputPath string, sumSlice []ProductSumDecline, title string) error {
	// 1. 读取模板
	f, err := excelize.OpenFile(templatePath)
	if err != nil {
		return err
	}
	defer f.Close()

	sheet := f.GetSheetName(0)
	if len(title) > 0 {
		// 写入标题
		f.SetCellValue(sheet, "A1", title)
	}
	// ---------------- 样式获取 ----------------
	// 模板第2行：数据行样式
	tplRowData := 3
	styleA2, err := f.GetCellStyle(sheet, fmt.Sprintf("A%d", tplRowData))
	if err != nil {
		styleA2 = 0
	}
	// B2和C2通常样式一致，这里取B2作为明细列样式
	styleB2, err := f.GetCellStyle(sheet, fmt.Sprintf("B%d", tplRowData))
	if err != nil {
		styleB2 = 0
	}
	styleC2, err := f.GetCellStyle(sheet, fmt.Sprintf("C%d", tplRowData))
	if err != nil {
		styleC2 = 0
	}
	styleD2, err := f.GetCellStyle(sheet, fmt.Sprintf("D%d", tplRowData))
	if err != nil {
		styleC2 = 0
	}
	//styleE2, err := f.GetCellStyle(sheet, fmt.Sprintf("E%d", tplRowData))
	//if err != nil {
	//	styleC2 = 0
	//}
	styleF2, err := f.GetCellStyle(sheet, fmt.Sprintf("F%d", tplRowData))
	if err != nil {
		styleC2 = 0
	}
	//styleG2, err := f.GetCellStyle(sheet, fmt.Sprintf("G%d", tplRowData))
	//if err != nil {
	//	styleC2 = 0
	//}

	rowHeightData, err := f.GetRowHeight(sheet, tplRowData)
	if err != nil {
		rowHeightData = 20
	}
	rowWidth := 25.00
	currentRow := 3
	pattern := `\$\{(.*?)\}`
	re := regexp.MustCompile(pattern)
	for _, product := range sumSlice {
		// 排序 ProductLoss
		var reseller []ProductSumReseller
		for _, p := range product.ProductSumReseller {
			reseller = append(reseller, p)
		}
		sort.Slice(reseller, func(i, j int) bool {
			return reseller[i].HistoryOneDiff < reseller[j].HistoryOneDiff
		})

		startRow := currentRow

		// 填充该经销商的所有产品
		for _, p := range reseller {
			// 设置行高
			var (
				oneDiff string
				twoDiff string
			)
			f.SetRowHeight(sheet, currentRow, rowHeightData)
			if p.HistoryOneDiff >= 0 {
				oneDiff = fmt.Sprintf("%s↑%d", RedStyle, p.HistoryOneDiff)
			} else {
				oneDiff = fmt.Sprintf("%s↓%d", GreenStyle, p.HistoryOneDiff)
			}
			if p.HistoryTwoDiff >= 0 {
				twoDiff = fmt.Sprintf("%s↑%d", RedStyle, p.HistoryTwoDiff)
			} else {
				twoDiff = fmt.Sprintf("%s↓%d", GreenStyle, p.HistoryTwoDiff)
			}
			matchesE := re.FindStringSubmatch(oneDiff)
			styleMap := make(map[string]string)

			if len(matchesE) != 2 {
				continue
			}
			for _, kv := range strings.Split(matchesE[1], ";") {
				kvParts := strings.Split(kv, ":")
				if len(kvParts) == 2 {
					styleMap[strings.TrimSpace(kvParts[0])] = strings.TrimSpace(kvParts[1])
				}
			}
			fontStyleIDE, _err := SetStyle(styleMap, f)
			if _err != nil {
				log.Errorf("set style failed: %v", _err)
			}
			f.SetCellStyle(sheet, fmt.Sprintf("E%d", currentRow), fmt.Sprintf("E%d", currentRow), fontStyleIDE)
			oneDiffValue := re.ReplaceAllString(oneDiff, "")
			matchesG := re.FindStringSubmatch(twoDiff)
			styleMapG := make(map[string]string)
			if len(matchesG) != 2 {
				continue
			}
			for _, kv := range strings.Split(matchesG[1], ";") {
				kvParts := strings.Split(kv, ":")
				if len(kvParts) == 2 {
					styleMapG[strings.TrimSpace(kvParts[0])] = strings.TrimSpace(kvParts[1])
				}
			}
			fontStyleIDG, _err := SetStyle(styleMapG, f)
			if _err != nil {
				log.Errorf("set style failed: %v", _err)
			}
			twoDiffValue := re.ReplaceAllString(twoDiff, "")
			f.SetCellStyle(sheet, fmt.Sprintf("G%d", currentRow), fmt.Sprintf("G%d", currentRow), fontStyleIDG)
			// 设置值
			//f.SetColWidth(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("A%d", currentRow), product.OfficialProductName)
			//f.SetColWidth(sheet, fmt.Sprintf("B%d", currentRow), fmt.Sprintf("B%d", currentRow), p.ResellerName)
			f.SetColWidth(sheet, fmt.Sprintf("C%d", currentRow), fmt.Sprintf("C%d", currentRow), rowWidth)
			f.SetColWidth(sheet, fmt.Sprintf("D%d", currentRow), fmt.Sprintf("D%d", currentRow), rowWidth)
			f.SetColWidth(sheet, fmt.Sprintf("E%d", currentRow), fmt.Sprintf("E%d", currentRow), rowWidth)
			f.SetColWidth(sheet, fmt.Sprintf("F%d", currentRow), fmt.Sprintf("F%d", currentRow), rowWidth)
			f.SetColWidth(sheet, fmt.Sprintf("G%d", currentRow), fmt.Sprintf("G%d", currentRow), rowWidth)

			f.SetCellValue(sheet, fmt.Sprintf("A%d", currentRow), product.OfficialProductName)
			f.SetCellValue(sheet, fmt.Sprintf("B%d", currentRow), p.ResellerName)
			f.SetCellValue(sheet, fmt.Sprintf("C%d", currentRow), p.CurrentNum)
			f.SetCellValue(sheet, fmt.Sprintf("D%d", currentRow), p.HistoryOneNum)
			f.SetCellValue(sheet, fmt.Sprintf("E%d", currentRow), oneDiffValue)
			f.SetCellValue(sheet, fmt.Sprintf("F%d", currentRow), p.HistoryTwoNum)
			f.SetCellValue(sheet, fmt.Sprintf("G%d", currentRow), twoDiffValue)

			// 设置样式
			if styleA2 != 0 {
				f.SetCellStyle(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("A%d", currentRow), styleA2)
			}
			if styleB2 != 0 {
				f.SetCellStyle(sheet, fmt.Sprintf("B%d", currentRow), fmt.Sprintf("B%d", currentRow), styleB2)
			}
			if styleC2 != 0 {
				f.SetCellStyle(sheet, fmt.Sprintf("C%d", currentRow), fmt.Sprintf("C%d", currentRow), styleC2)
			}
			if styleD2 != 0 {
				f.SetCellStyle(sheet, fmt.Sprintf("D%d", currentRow), fmt.Sprintf("D%d", currentRow), styleC2)
			}

			if styleF2 != 0 {
				f.SetCellStyle(sheet, fmt.Sprintf("F%d", currentRow), fmt.Sprintf("F%d", currentRow), styleC2)
			}

			currentRow++
		}

		endRow := currentRow - 1
		// 合并单元格 (如果多于1行)
		if endRow > startRow {
			f.MergeCell(sheet, fmt.Sprintf("A%d", startRow), fmt.Sprintf("A%d", endRow))
		}
	}

	// 6. 保存
	return f.SaveAs(outputPath)
}
