package controller

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/QuantumNous/new-api/common"
	"github.com/QuantumNous/new-api/model"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
)

const maxModelImportFileSize = 10 << 20

type modelImportRowResult struct {
	Row       int    `json:"row"`
	ModelName string `json:"model_name,omitempty"`
	Status    string `json:"status"`
	Message   string `json:"message,omitempty"`
}

type modelImportResult struct {
	Created int                    `json:"created"`
	Updated int                    `json:"updated"`
	Skipped int                    `json:"skipped"`
	Failed  int                    `json:"failed"`
	Rows    []modelImportRowResult `json:"rows"`
}

// ImportModelsMeta imports model metadata from the first worksheet of an xlsx file.
func ImportModelsMeta(c *gin.Context) {
	fileHeader, err := c.FormFile("file")
	if err != nil {
		common.ApiErrorMsg(c, "请上传 Excel 文件，字段名为 file")
		return
	}
	if fileHeader.Size > maxModelImportFileSize {
		common.ApiErrorMsg(c, "Excel 文件不能超过 10MB")
		return
	}

	file, err := fileHeader.Open()
	if err != nil {
		common.ApiError(c, err)
		return
	}
	defer file.Close()

	data, err := io.ReadAll(file)
	if err != nil {
		common.ApiError(c, err)
		return
	}

	rows, err := readFirstExcelSheet(data)
	if err != nil {
		common.ApiErrorMsg(c, "读取 Excel 失败: "+err.Error())
		return
	}
	if len(rows) < 2 {
		common.ApiErrorMsg(c, "Excel 至少需要包含表头和一行数据")
		return
	}

	headers := make(map[string]int)
	for i, header := range rows[0] {
		normalized := normalizeModelImportHeader(header)
		if normalized != "" {
			headers[normalized] = i
		}
	}
	if _, ok := headers["model_name"]; !ok {
		common.ApiErrorMsg(c, "Excel 表头缺少必填列 model_name")
		return
	}

	overwrite := strings.EqualFold(c.Query("overwrite"), "true")
	result := importModelRows(rows[1:], headers, overwrite)
	if result.Created > 0 || result.Updated > 0 {
		model.RefreshPricing()
	}
	common.ApiSuccess(c, result)
}

func importModelRows(rows [][]string, headers map[string]int, overwrite bool) modelImportResult {
	result := modelImportResult{
		Rows: make([]modelImportRowResult, 0, len(rows)),
	}
	vendorIDByName := make(map[string]int)

	for i, row := range rows {
		rowNumber := i + 2
		if isEmptyXLSXRow(row) {
			continue
		}

		m, err := buildModelFromImportRow(row, headers, vendorIDByName)
		rowResult := modelImportRowResult{Row: rowNumber, ModelName: m.ModelName}
		if err != nil {
			rowResult.Status = "failed"
			rowResult.Message = err.Error()
			result.Failed++
			result.Rows = append(result.Rows, rowResult)
			continue
		}

		var existing model.Model
		err = model.DB.Where("model_name = ?", m.ModelName).First(&existing).Error
		if err == nil {
			if !overwrite {
				rowResult.Status = "skipped"
				rowResult.Message = "模型名称已存在"
				result.Skipped++
				result.Rows = append(result.Rows, rowResult)
				continue
			}
			m.Id = existing.Id
			if err := m.Update(); err != nil {
				rowResult.Status = "failed"
				rowResult.Message = err.Error()
				result.Failed++
			} else {
				rowResult.Status = "updated"
				result.Updated++
			}
			result.Rows = append(result.Rows, rowResult)
			continue
		}
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			rowResult.Status = "failed"
			rowResult.Message = err.Error()
			result.Failed++
			result.Rows = append(result.Rows, rowResult)
			continue
		}

		if dup, err := model.IsModelNameDuplicated(0, m.ModelName); err != nil {
			rowResult.Status = "failed"
			rowResult.Message = err.Error()
			result.Failed++
			result.Rows = append(result.Rows, rowResult)
			continue
		} else if dup {
			rowResult.Status = "skipped"
			rowResult.Message = "模型名称已存在"
			result.Skipped++
			result.Rows = append(result.Rows, rowResult)
			continue
		}

		if err := m.Insert(); err != nil {
			rowResult.Status = "failed"
			rowResult.Message = err.Error()
			result.Failed++
		} else {
			rowResult.Status = "created"
			result.Created++
		}
		result.Rows = append(result.Rows, rowResult)
	}

	return result
}

func buildModelFromImportRow(row []string, headers map[string]int, vendorIDByName map[string]int) (model.Model, error) {
	m := model.Model{
		Status:       1,
		SyncOfficial: 1,
		NameRule:     model.NameRuleExact,
	}

	m.ModelName = getImportCell(row, headers, "model_name")
	if m.ModelName == "" {
		return m, fmt.Errorf("模型名称不能为空")
	}
	m.Description = getImportCell(row, headers, "description")
	m.Icon = getImportCell(row, headers, "icon")
	m.Tags = getImportCell(row, headers, "tags")
	m.Endpoints = getImportCell(row, headers, "endpoints")

	if vendorName := getImportCell(row, headers, "vendor_name"); vendorName != "" {
		vendorID, err := getImportVendorID(vendorName, vendorIDByName)
		if err != nil {
			return m, err
		}
		m.VendorID = vendorID
	}
	if raw := getImportCell(row, headers, "status"); raw != "" {
		status, err := parseImportBoolInt(raw)
		if err != nil {
			return m, fmt.Errorf("status 格式错误")
		}
		m.Status = status
	}
	if raw := getImportCell(row, headers, "sync_official"); raw != "" {
		syncOfficial, err := parseImportBoolInt(raw)
		if err != nil {
			return m, fmt.Errorf("sync_official 格式错误")
		}
		m.SyncOfficial = syncOfficial
	}
	if raw := getImportCell(row, headers, "name_rule"); raw != "" {
		nameRule, err := parseModelNameRule(raw)
		if err != nil {
			return m, err
		}
		m.NameRule = nameRule
	}

	return m, nil
}

func getImportVendorID(vendorName string, vendorIDByName map[string]int) (int, error) {
	if vendorID, ok := vendorIDByName[vendorName]; ok {
		return vendorID, nil
	}

	var vendor model.Vendor
	if err := model.DB.Select("id").Where("name = ?", vendorName).First(&vendor).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return 0, fmt.Errorf("供应商不存在：%s", vendorName)
		}
		return 0, err
	}

	vendorIDByName[vendorName] = vendor.Id
	return vendor.Id, nil
}

func readFirstExcelSheet(data []byte) ([][]string, error) {
	workbook, err := excelize.OpenReader(bytes.NewReader(data))
	if err != nil {
		return nil, err
	}
	defer workbook.Close()

	sheets := workbook.GetSheetList()
	if len(sheets) == 0 {
		return nil, fmt.Errorf("未找到工作表")
	}
	return workbook.GetRows(sheets[0], excelize.Options{RawCellValue: true})
}

func normalizeModelImportHeader(header string) string {
	key := strings.ToLower(strings.TrimSpace(header))
	key = strings.ReplaceAll(key, " ", "")
	key = strings.ReplaceAll(key, "-", "_")
	switch key {
	case "model_name", "modelname", "模型名称", "模型名", "名称":
		return "model_name"
	case "description", "desc", "描述", "说明":
		return "description"
	case "icon", "图标":
		return "icon"
	case "tags", "tag", "标签":
		return "tags"
	case "vendor_name", "vendorname", "vendor", "供应商名称", "供应商":
		return "vendor_name"
	case "endpoints", "endpoint", "端点":
		return "endpoints"
	case "status", "状态", "启用":
		return "status"
	case "sync_official", "syncofficial", "官方同步", "同步官方":
		return "sync_official"
	case "name_rule", "namerule", "匹配规则", "名称匹配规则":
		return "name_rule"
	default:
		return ""
	}
}

func getImportCell(row []string, headers map[string]int, key string) string {
	index, ok := headers[key]
	if !ok || index < 0 || index >= len(row) {
		return ""
	}
	return strings.TrimSpace(row[index])
}

func isEmptyXLSXRow(row []string) bool {
	for _, cell := range row {
		if strings.TrimSpace(cell) != "" {
			return false
		}
	}
	return true
}

func parseImportInt(raw string) (int, error) {
	value := strings.TrimSpace(raw)
	if value == "" {
		return 0, nil
	}
	if intValue, err := strconv.Atoi(value); err == nil {
		return intValue, nil
	}
	floatValue, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return 0, err
	}
	return int(floatValue), nil
}

func parseImportBoolInt(raw string) (int, error) {
	value := strings.ToLower(strings.TrimSpace(raw))
	switch value {
	case "true", "yes", "y", "on", "启用", "是", "1":
		return 1, nil
	case "false", "no", "n", "off", "禁用", "否", "0":
		return 0, nil
	default:
		return parseImportInt(value)
	}
}

func parseModelNameRule(raw string) (int, error) {
	value := strings.ToLower(strings.TrimSpace(raw))
	switch value {
	case "", "0", "exact", "精确", "精确名称匹配":
		return model.NameRuleExact, nil
	case "1", "prefix", "前缀", "前缀名称匹配":
		return model.NameRulePrefix, nil
	case "2", "contains", "contain", "包含", "包含名称匹配":
		return model.NameRuleContains, nil
	case "3", "suffix", "后缀", "后缀名称匹配":
		return model.NameRuleSuffix, nil
	default:
		return 0, fmt.Errorf("name_rule 格式错误")
	}
}
