package controller

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/QuantumNous/new-api/common"
	"github.com/QuantumNous/new-api/model"
	"github.com/QuantumNous/new-api/setting/ratio_setting"
	"github.com/gin-gonic/gin"
)

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

type modelPricingImportResult struct {
	Updated    int                           `json:"updated"`
	PerToken   int                           `json:"per_token"`
	PerRequest int                           `json:"per_request"`
	Failed     int                           `json:"failed"`
	Rows       []modelPricingImportRowResult `json:"rows"`
}

type modelPricingImportValues struct {
	modelName        string
	inputPrice       *float64
	completionPrice  *float64
	cachePrice       *float64
	createCachePrice *float64
	imagePrice       *float64
	audioInputPrice  *float64
	audioOutputPrice *float64
	fixedPrice       *float64
}

func ImportModelPricing(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 := normalizeModelPricingImportHeader(header)
		if normalized != "" {
			headers[normalized] = i
		}
	}
	if _, ok := headers["model_name"]; !ok {
		common.ApiErrorMsg(c, "Excel 表头缺少必填列 model_name")
		return
	}

	result, values, err := parseModelPricingImportRows(rows[1:], headers)
	if err != nil {
		common.ApiError(c, err)
		return
	}
	if result.Updated == 0 {
		common.ApiSuccess(c, result)
		return
	}

	if err := saveImportedModelPricing(values); err != nil {
		common.ApiError(c, err)
		return
	}
	model.RefreshPricing()
	common.ApiSuccess(c, result)
}

func parseModelPricingImportRows(rows [][]string, headers map[string]int) (modelPricingImportResult, []modelPricingImportValues, error) {
	result := modelPricingImportResult{
		Rows: make([]modelPricingImportRowResult, 0, len(rows)),
	}
	values := make([]modelPricingImportValues, 0, len(rows))

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

		item, err := buildModelPricingFromImportRow(row, headers)
		rowResult := modelPricingImportRowResult{
			Row:       rowNumber,
			ModelName: item.modelName,
		}
		if err != nil {
			rowResult.Status = "failed"
			rowResult.Message = err.Error()
			result.Failed++
			result.Rows = append(result.Rows, rowResult)
			continue
		}

		if item.fixedPrice != nil {
			rowResult.Mode = "per_request"
			result.PerRequest++
		} else {
			rowResult.Mode = "per_token"
			result.PerToken++
		}
		rowResult.Status = "updated"
		result.Updated++
		result.Rows = append(result.Rows, rowResult)
		values = append(values, item)
	}

	return result, values, nil
}

func buildModelPricingFromImportRow(row []string, headers map[string]int) (modelPricingImportValues, error) {
	item := modelPricingImportValues{
		modelName: getImportCell(row, headers, "model_name"),
	}
	if item.modelName == "" {
		return item, fmt.Errorf("模型名称不能为空")
	}

	var err error
	item.inputPrice, err = parseOptionalImportPrice(row, headers, "input_price")
	if err != nil {
		return item, fmt.Errorf("input_price 格式错误")
	}
	item.completionPrice, err = parseOptionalImportPrice(row, headers, "completion_price")
	if err != nil {
		return item, fmt.Errorf("completion_price 格式错误")
	}
	item.cachePrice, err = parseOptionalImportPrice(row, headers, "cache_price")
	if err != nil {
		return item, fmt.Errorf("cache_price 格式错误")
	}
	item.createCachePrice, err = parseOptionalImportPrice(row, headers, "create_cache_price")
	if err != nil {
		return item, fmt.Errorf("create_cache_price 格式错误")
	}
	item.imagePrice, err = parseOptionalImportPrice(row, headers, "image_price")
	if err != nil {
		return item, fmt.Errorf("image_price 格式错误")
	}
	item.audioInputPrice, err = parseOptionalImportPrice(row, headers, "audio_input_price")
	if err != nil {
		return item, fmt.Errorf("audio_input_price 格式错误")
	}
	item.audioOutputPrice, err = parseOptionalImportPrice(row, headers, "audio_output_price")
	if err != nil {
		return item, fmt.Errorf("audio_output_price 格式错误")
	}
	item.fixedPrice, err = parseOptionalImportPrice(row, headers, "fixed_price")
	if err != nil {
		return item, fmt.Errorf("fixed_price 格式错误")
	}

	if item.fixedPrice != nil {
		return item, nil
	}
	if item.inputPrice == nil {
		return item, fmt.Errorf("按次计费价格为空时，按量计费输入价格不能为空")
	}
	if *item.inputPrice == 0 {
		if item.completionPrice != nil ||
			item.cachePrice != nil ||
			item.createCachePrice != nil ||
			item.imagePrice != nil ||
			item.audioInputPrice != nil ||
			item.audioOutputPrice != nil {
			return item, fmt.Errorf("输入价格为 0 时不能填写输出/缓存/图片/音频价格")
		}
		return item, nil
	}
	if item.audioOutputPrice != nil && item.audioInputPrice == nil {
		return item, fmt.Errorf("填写音频输出价格时，音频输入价格不能为空")
	}
	if item.audioInputPrice != nil && *item.audioInputPrice == 0 && item.audioOutputPrice != nil {
		return item, fmt.Errorf("音频输入价格为 0 时不能填写音频输出价格")
	}

	return item, nil
}

func parseOptionalImportPrice(row []string, headers map[string]int, key string) (*float64, error) {
	raw := getImportCell(row, headers, key)
	if raw == "" {
		return nil, nil
	}
	value := strings.TrimSpace(raw)
	value = strings.TrimPrefix(value, "$")
	value = strings.ReplaceAll(value, ",", "")
	num, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return nil, err
	}
	if num < 0 {
		return nil, fmt.Errorf("price must be >= 0")
	}
	return &num, nil
}

func normalizeModelPricingImportHeader(header string) string {
	key := strings.ToLower(strings.TrimSpace(header))
	key = strings.ReplaceAll(key, " ", "")
	key = strings.ReplaceAll(key, "-", "_")
	key = strings.ReplaceAll(key, "/", "_")
	switch key {
	case "model_name", "modelname", "模型名称", "模型名", "名称":
		return "model_name"
	case "input_price", "inputprice", "prompt_price", "promptprice", "按量计费", "输入价格", "提示价格":
		return "input_price"
	case "completion_price", "completionprice", "output_price", "outputprice", "输出价格", "补全价格":
		return "completion_price"
	case "cache_price", "cacheprice", "cache_read_price", "缓存价格", "缓存命中价格":
		return "cache_price"
	case "create_cache_price", "createcacheprice", "cache_write_price", "缓存创建价格", "缓存写入价格":
		return "create_cache_price"
	case "image_price", "imageprice", "图片价格", "图像价格":
		return "image_price"
	case "audio_input_price", "audioinputprice", "audio_price", "音频输入价格", "音频价格":
		return "audio_input_price"
	case "audio_output_price", "audiooutputprice", "audio_completion_price", "音频输出价格", "音频补全价格":
		return "audio_output_price"
	case "fixed_price", "fixedprice", "per_request_price", "perrequestprice", "model_price", "按次计费", "按次价格", "固定价格":
		return "fixed_price"
	default:
		return ""
	}
}

func saveImportedModelPricing(values []modelPricingImportValues) error {
	modelPriceMap := ratio_setting.GetModelPriceCopy()
	modelRatioMap := ratio_setting.GetModelRatioCopy()
	completionRatioMap := ratio_setting.GetCompletionRatioCopy()
	cacheRatioMap := ratio_setting.GetCacheRatioMap()
	createCacheRatioMap := ratio_setting.GetCreateCacheRatioMap()
	imageRatioMap := ratio_setting.GetImageRatioCopy()
	audioRatioMap := ratio_setting.GetAudioRatioCopy()
	audioCompletionRatioMap := ratio_setting.GetAudioCompletionRatioCopy()

	for _, item := range values {
		if item.fixedPrice != nil {
			modelPriceMap[item.modelName] = *item.fixedPrice
			delete(modelRatioMap, item.modelName)
			delete(completionRatioMap, item.modelName)
			delete(cacheRatioMap, item.modelName)
			delete(createCacheRatioMap, item.modelName)
			delete(imageRatioMap, item.modelName)
			delete(audioRatioMap, item.modelName)
			delete(audioCompletionRatioMap, item.modelName)
			continue
		}

		delete(modelPriceMap, item.modelName)
		modelRatioMap[item.modelName] = normalizeImportedPrice(*item.inputPrice / 2)
		setRatioFromPrice(completionRatioMap, item.modelName, item.completionPrice, *item.inputPrice)
		setRatioFromPrice(cacheRatioMap, item.modelName, item.cachePrice, *item.inputPrice)
		setRatioFromPrice(createCacheRatioMap, item.modelName, item.createCachePrice, *item.inputPrice)
		setRatioFromPrice(imageRatioMap, item.modelName, item.imagePrice, *item.inputPrice)
		setRatioFromPrice(audioRatioMap, item.modelName, item.audioInputPrice, *item.inputPrice)
		if item.audioOutputPrice == nil {
			delete(audioCompletionRatioMap, item.modelName)
		} else {
			audioBase := *item.inputPrice
			if item.audioInputPrice != nil {
				audioBase = *item.audioInputPrice
			}
			audioCompletionRatioMap[item.modelName] = normalizeImportedPrice(*item.audioOutputPrice / audioBase)
		}
	}

	optionValues := map[string]string{}
	for key, value := range map[string]map[string]float64{
		"ModelPrice":           modelPriceMap,
		"ModelRatio":           modelRatioMap,
		"CompletionRatio":      completionRatioMap,
		"CacheRatio":           cacheRatioMap,
		"CreateCacheRatio":     createCacheRatioMap,
		"ImageRatio":           imageRatioMap,
		"AudioRatio":           audioRatioMap,
		"AudioCompletionRatio": audioCompletionRatioMap,
	} {
		jsonBytes, err := common.Marshal(value)
		if err != nil {
			return err
		}
		optionValues[key] = string(jsonBytes)
	}

	return model.UpdateOptionsBulk(optionValues)
}

func setRatioFromPrice(target map[string]float64, modelName string, price *float64, inputPrice float64) {
	if price == nil {
		delete(target, modelName)
		return
	}
	target[modelName] = normalizeImportedPrice(*price / inputPrice)
}

func normalizeImportedPrice(value float64) float64 {
	normalized, err := strconv.ParseFloat(strconv.FormatFloat(value, 'f', 12, 64), 64)
	if err != nil {
		return value
	}
	return normalized
}
