package controller

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/songquanpeng/one-api/common"
	"github.com/songquanpeng/one-api/common/config"
)

func DownloadServerConfig(c *gin.Context) {
	configs := collectServerConfigs()
	var lines []string

	lines = append(lines, "# One API Server Configuration")
	lines = append(lines, "# Generated at runtime - download from settings page")
	lines = append(lines, "")

	// Group by category for readability
	categories := []string{"database", "redis", "performance", "network", "ratelimit", "metrics", "other"}
	categoryNames := map[string]string{
		"database":     "# ===== Database =====\n",
		"redis":        "\n# ===== Redis =====\n",
		"performance":  "\n# ===== Performance =====\n",
		"network":      "\n# ===== Network =====\n",
		"ratelimit":    "\n# ===== Rate Limit =====\n",
		"metrics":      "\n# ===== Metrics =====\n",
		"other":        "\n# ===== Other =====\n",
	}

	for _, cat := range categories {
		lines = append(lines, categoryNames[cat])
		for _, item := range configs {
			if item.Category != cat {
				continue
			}
			// Skip the virtual db_type key
			if item.Key == "db_type" {
				continue
			}
			// Get the actual value from env/runtime for the download
			actualValue := getActualConfigValue(item.Key)
			if item.Key == "SESSION_SECRET" || item.Key == "REDIS_PASSWORD" ||
				strings.HasSuffix(item.Key, "TOKEN") || strings.HasSuffix(item.Key, "TOKEN") ||
				strings.HasSuffix(item.Key, "SECRET") || strings.HasSuffix(item.Key, "Secret") ||
				item.Key == "SQL_DSN" || item.Key == "LOG_SQL_DSN" ||
				item.Key == "REDIS_CONN_STRING" || item.Key == "HTTPS_PROXY" {
				// Include masked values for secrets
				lines = append(lines, fmt.Sprintf("# %s=%s", item.Key, item.Value))
				lines = append(lines, fmt.Sprintf("# %s (masked above, set manually if needed)", item.Key))
			} else {
				lines = append(lines, fmt.Sprintf("%s=%s", item.Key, actualValue))
			}
		}
	}

	content := strings.Join(lines, "\n")
	c.Header("Content-Disposition", "attachment; filename=server-config.env")
	c.Header("Content-Type", "text/plain; charset=utf-8")
	c.String(http.StatusOK, content)
}

func ImportServerConfig(c *gin.Context) {
	file, _, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "请上传 .env 配置文件",
		})
		return
	}
	defer file.Close()

	content, err := io.ReadAll(file)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "读取文件失败：" + err.Error(),
		})
		return
	}

	// Validate basic .env format
	lines := strings.Split(string(content), "\n")
	validLines := 0
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		if strings.Contains(line, "=") {
			validLines++
		}
	}

	if validLines == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "无效的 .env 文件格式，未找到有效的配置项",
		})
		return
	}

	// Determine the .env file path
	envPath := ".env"
	if p := os.Getenv("SERVER_CONFIG_PATH"); p != "" {
		envPath = p
	}

	err = os.WriteFile(envPath, content, 0644)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "写入配置文件失败：" + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": fmt.Sprintf("配置文件已保存到 %s，请重启服务以生效。", envPath),
	})
}

func getActualConfigValue(key string) string {
	switch key {
	case "PORT":
		return strconv.Itoa(*common.Port)
	case "SESSION_SECRET":
		return config.SessionSecret
	case "SQL_DSN", "LOG_SQL_DSN", "REDIS_CONN_STRING", "REDIS_PASSWORD",
		"REDIS_MASTER_NAME", "NODE_TYPE", "POLLING_INTERVAL",
		"GIN_MODE", "FRONTEND_BASE_URL", "CHANNEL_TEST_FREQUENCY",
		"INITIAL_ROOT_TOKEN", "INITIAL_ROOT_ACCESS_TOKEN", "HTTPS_PROXY":
		return os.Getenv(key)
	case "SQLITE_PATH":
		if os.Getenv("SQLITE_PATH") != "" {
			return os.Getenv("SQLITE_PATH")
		}
		return common.SQLitePath
	case "SQLITE_BUSY_TIMEOUT":
		return strconv.Itoa(common.SQLiteBusyTimeout)
	case "SQL_MAX_IDLE_CONNS":
		if v := os.Getenv("SQL_MAX_IDLE_CONNS"); v != "" {
			return v
		}
		return "100"
	case "SQL_MAX_OPEN_CONNS":
		if v := os.Getenv("SQL_MAX_OPEN_CONNS"); v != "" {
			return v
		}
		return "1000"
	case "SQL_MAX_LIFETIME":
		if v := os.Getenv("SQL_MAX_LIFETIME"); v != "" {
			return v
		}
		return "60"
	case "SYNC_FREQUENCY":
		return strconv.Itoa(config.SyncFrequency)
	case "DEBUG":
		return strconv.FormatBool(config.DebugEnabled)
	case "DEBUG_SQL":
		return strconv.FormatBool(config.DebugSQLEnabled)
	case "MEMORY_CACHE_ENABLED":
		return strconv.FormatBool(config.MemoryCacheEnabled)
	case "BATCH_UPDATE_ENABLED":
		return strconv.FormatBool(config.BatchUpdateEnabled)
	case "BATCH_UPDATE_INTERVAL":
		return strconv.Itoa(config.BatchUpdateInterval)
	case "RELAY_TIMEOUT":
		return strconv.Itoa(config.RelayTimeout)
	case "RELAY_PROXY":
		return config.RelayProxy
	case "USER_CONTENT_REQUEST_PROXY":
		return config.UserContentRequestProxy
	case "USER_CONTENT_REQUEST_TIMEOUT":
		return strconv.Itoa(config.UserContentRequestTimeout)
	case "GEMINI_SAFETY_SETTING":
		return config.GeminiSafetySetting
	case "GEMINI_VERSION":
		return config.GeminiVersion
	case "THEME":
		return config.Theme
	case "GLOBAL_API_RATE_LIMIT":
		return strconv.Itoa(config.GlobalApiRateLimitNum)
	case "GLOBAL_WEB_RATE_LIMIT":
		return strconv.Itoa(config.GlobalWebRateLimitNum)
	case "ENABLE_METRIC":
		return strconv.FormatBool(config.EnableMetric)
	case "METRIC_QUEUE_SIZE":
		return strconv.Itoa(config.MetricQueueSize)
	case "METRIC_SUCCESS_RATE_THRESHOLD":
		return strconv.FormatFloat(config.MetricSuccessRateThreshold, 'f', 2, 64)
	case "ONLY_ONE_LOG_FILE":
		return strconv.FormatBool(config.OnlyOneLogFile)
	case "ENFORCE_INCLUDE_USAGE":
		return strconv.FormatBool(config.EnforceIncludeUsage)
	case "TEST_PROMPT":
		return config.TestPrompt
	}
	return ""
}