package excel

import (
	"fmt"
	"github.com/xuri/excelize/v2"
	"io"
	"math"
	"net/http"
	"strconv"
	"time"
)

// ExcelGenerator 通用Excel生成器
type ExcelGenerator struct {
	file       *excelize.File
	sheetName  string
	headers    []string
	headerMap  map[string]string // 表头映射（英文字段名->中文显示名）
	currentRow int               // 当前行号
}

// NewExcelGenerator 创建新的Excel生成器
func NewExcelGenerator(sheetName string, headers []string, headerMap map[string]string) *ExcelGenerator {
	f := excelize.NewFile()
	// 默认sheet名称是Sheet1，如果传入的是其他名称，则创建新sheet并删除默认sheet
	defaultSheetName := "Sheet1"
	if sheetName != defaultSheetName {
		f.NewSheet(sheetName)
		f.DeleteSheet(defaultSheetName)
	}
	
	return &ExcelGenerator{
		file:       f,
		sheetName:  sheetName,
		headers:    headers,
		headerMap:  headerMap,
		currentRow: 1, // 从第1行开始（通常第1行是表头）
	}
}

// WriteHeaders 写入表头
func (g *ExcelGenerator) WriteHeaders() error {
	// 写入表头
	for i, header := range g.headers {
		// 获取对应的显示名，如果没有映射则使用原字段名
		displayName, exists := g.headerMap[header]
		if !exists {
			displayName = header
		}
		
		cell := fmt.Sprintf("%s%d", columnName(i), g.currentRow)
		if err := g.file.SetCellValue(g.sheetName, cell, displayName); err != nil {
			return err
		}
		
		// 设置表头样式（加粗、居中等）
		style, err := g.file.NewStyle(&excelize.Style{
			Font: &excelize.Font{
				Bold: true,
			},
			Alignment: &excelize.Alignment{
				Horizontal: "center",
				Vertical:   "center",
			},
		})
		if err != nil {
			return err
		}
		if err := g.file.SetCellStyle(g.sheetName, cell, cell, style); err != nil {
			return err
		}
	}
	
	g.currentRow++ // 表头写完后，行号+1
	return nil
}

// WriteRows 写入多行数据
func (g *ExcelGenerator) WriteRows(data []map[string]interface{}) error {
	for _, row := range data {
		if err := g.WriteRow(row); err != nil {
			return err
		}
	}
	return nil
}

// WriteRow 写入单行数据
func (g *ExcelGenerator) WriteRow(rowData map[string]interface{}) error {
	for i, field := range g.headers {
		value, exists := rowData[field]
		if !exists {
			value = "" // 如果数据中不存在该字段，则写入空值
		}
		
		cell := fmt.Sprintf("%s%d", columnName(i), g.currentRow)
		
		// 根据不同的数据类型处理
		switch v := value.(type) {
		case time.Time:
			// 时间格式化为 YYYY-MM-DD HH:MM:SS
			if err := g.file.SetCellValue(g.sheetName, cell, v.Format("2006-01-02 15:04:05")); err != nil {
				return err
			}
		default:
			if err := g.file.SetCellValue(g.sheetName, cell, v); err != nil {
				return err
			}
		}
	}
	
	g.currentRow++ // 一行写完后，行号+1
	return nil
}

// SaveToWriter 保存到io.Writer接口
func (g *ExcelGenerator) SaveToWriter(w io.Writer) error {
	return g.file.Write(w)
}

// SaveToBuffer 保存到内存
func (g *ExcelGenerator) SaveToBuffer() ([]byte, error) {
	buffer, err := g.file.WriteToBuffer()
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}

// columnName 将列索引转换为Excel列名（A, B, C, ... Z, AA, AB, ...）
func columnName(colIndex int) string {
	if colIndex < 26 {
		return string('A' + colIndex)
	}
	
	// 超过26列时需要用两个或更多字母表示
	result := ""
	for colIndex >= 0 {
		remainder := colIndex % 26
		result = string('A'+remainder) + result
		colIndex = colIndex/26 - 1
		if colIndex < 0 {
			break
		}
	}
	
	return result
}

// TransferOption 传输选项
type TransferOption struct {
	FileName    string
	ContentType string
}

// ExportType 导出类型枚举
type ExportType int

const (
	// ExportTypeNormal 普通导出（小文件，加载到内存后直接传输）
	ExportTypeNormal ExportType = iota
	
	// ExportTypeStream 流式导出（大文件，流式传输避免占用过多内存）
	ExportTypeStream
	
	// ExportTypeChunk 分块导出（超大文件，分块处理并传输）
	ExportTypeChunk
)

// SmartExport 智能选择导出方式
// dataCount: 数据条数
// rowSize: 每行数据的估计大小（字节数）
func SmartExport(dataCount int, rowSize int) ExportType {
	// 估算导出文件大小（表头+数据）
	estimatedSize := (dataCount + 1) * rowSize
	
	// 根据估算大小选择不同的导出方式
	switch {
	case estimatedSize <= 5*1024*1024: // 5MB以下用普通导出
		return ExportTypeNormal
		
	case estimatedSize <= 50*1024*1024: // 5MB-50MB用流式导出
		return ExportTypeStream
		
	default: // 超过50MB用分块导出
		return ExportTypeChunk
	}
}

// NormalExport 普通导出（小文件，一次性加载到内存）
func NormalExport(g *ExcelGenerator, w http.ResponseWriter, option TransferOption) error {
	// 设置响应头
	w.Header().Set("Content-Type", option.ContentType)
	w.Header().Set("Content-Disposition", "attachment; filename="+option.FileName)
	
	// 直接写入响应
	return g.SaveToWriter(w)
}

// StreamExport 流式导出（大文件，流式传输）
func StreamExport(g *ExcelGenerator, w http.ResponseWriter, option TransferOption) error {
	// 设置响应头
	w.Header().Set("Content-Type", option.ContentType)
	w.Header().Set("Content-Disposition", "attachment; filename="+option.FileName)
	w.Header().Set("Transfer-Encoding", "chunked")
	
	// 流式写入
	return g.SaveToWriter(w)
}

// ChunkExport 分块导出（超大文件）
// 这个方法需要配合前端实现，例如通过分页API多次获取数据并合并
func ChunkExport(w http.ResponseWriter, option TransferOption, totalRecords int, pageSize int) {
	totalPages := int(math.Ceil(float64(totalRecords) / float64(pageSize)))
	
	// 设置响应头
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Total-Pages", strconv.Itoa(totalPages))
	w.Header().Set("X-Total-Records", strconv.Itoa(totalRecords))
	w.Header().Set("X-Page-Size", strconv.Itoa(pageSize))
	
	// 返回分块导出信息
	w.Write([]byte(fmt.Sprintf(`{
		"message": "File is too large for direct download. Please use paginated export.",
		"total_records": %d,
		"total_pages": %d,
		"page_size": %d
	}`, totalRecords, totalPages, pageSize)))
}
