package main

import (
	"embed"
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"
	"strings"
	"verification-platform-backend/internal/config"
	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/middleware"
	"verification-platform-backend/internal/router"
	"verification-platform-backend/internal/service"
	"verification-platform-backend/pkg/logger"

	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/bcrypt"
)

//go:embed embedded/dist/*
var embeddedFiles embed.FS

func main() {
	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "list-admin":
			listAdmins()
		case "reset-password":
			resetPassword()
		case "create-admin":
			createAdmin()
		case "help", "-h", "--help":
			printHelp()
		default:
			fmt.Printf("未知命令: %s\n", os.Args[1])
			printHelp()
			os.Exit(1)
		}
		return
	}

	startServer()
}

func printHelp() {
	fmt.Println("用法:")
	fmt.Println("  verify                    启动服务器")
	fmt.Println("  verify list-admin         列出所有管理员账号")
	fmt.Println("  verify reset-password <用户名> [新密码]  重置管理员密码")
	fmt.Println("  verify create-admin <用户名> <密码> [邮箱]  创建新管理员")
	fmt.Println("  verify help               显示帮助信息")
	fmt.Println()
	fmt.Println("示例:")
	fmt.Println("  verify list-admin")
	fmt.Println("  verify reset-password admin")
	fmt.Println("  verify reset-password admin newpass")
	fmt.Println("  verify create-admin newadmin password123 admin@example.com")
}

func listAdmins() {
	config.Init()
	database.Init()

	var users []struct {
		ID        uint
		Username  string
		Email     *string
		Role      string
		Status    string
		CreatedAt string
	}

	if err := database.DB.Table("users").Where("role = ?", "admin").Find(&users).Error; err != nil {
		fmt.Printf("错误: 查询失败 - %v\n", err)
		os.Exit(1)
	}

	if len(users) == 0 {
		fmt.Println("没有找到管理员账号")
		return
	}

	fmt.Println("管理员账号列表:")
	fmt.Println("----------------------------------------")
	for _, u := range users {
		email := ""
		if u.Email != nil {
			email = *u.Email
		}
		fmt.Printf("ID: %d  用户名: %s  邮箱: %s  状态: %s\n", u.ID, u.Username, email, u.Status)
	}
	fmt.Println("----------------------------------------")
}

func createAdmin() {
	config.Init()
	database.Init()

	if len(os.Args) < 4 {
		fmt.Println("用法: verify create-admin <用户名> <密码> [邮箱]")
		os.Exit(1)
	}

	username := os.Args[2]
	password := os.Args[3]
	email := ""
	if len(os.Args) >= 5 {
		email = os.Args[4]
	}

	if len(password) < 6 {
		fmt.Println("错误: 密码长度至少6位")
		os.Exit(1)
	}

	var count int64
	database.DB.Table("users").Where("username = ?", username).Count(&count)
	if count > 0 {
		fmt.Printf("错误: 用户名 '%s' 已存在\n", username)
		os.Exit(1)
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		fmt.Printf("错误: 密码加密失败 - %v\n", err)
		os.Exit(1)
	}

	emailPtr := (*string)(nil)
	if email != "" {
		emailPtr = &email
	}

	if err := database.DB.Table("users").Create(map[string]interface{}{
		"username": username,
		"password": string(hashedPassword),
		"email":    emailPtr,
		"role":     "admin",
		"status":   "active",
	}).Error; err != nil {
		fmt.Printf("错误: 创建失败 - %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("成功: 管理员账号 '%s' 已创建\n", username)
}

func resetPassword() {
	config.Init()
	database.Init()

	if len(os.Args) < 3 {
		fmt.Println("用法: verify reset-password <用户名> [新密码]")
		os.Exit(1)
	}

	username := os.Args[2]
	newPassword := ""
	if len(os.Args) >= 4 {
		newPassword = os.Args[3]
	}

	var user struct {
		ID       uint
		Username string
		Role     string
	}

	if err := database.DB.Table("users").Where("username = ? AND role = ?", username, "admin").First(&user).Error; err != nil {
		fmt.Printf("错误: 未找到管理员用户 '%s'\n", username)
		os.Exit(1)
	}

	if newPassword == "" {
		newPassword = generateRandomPassword(12)
	}

	if len(newPassword) < 6 {
		fmt.Println("错误: 密码长度至少6位")
		os.Exit(1)
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		fmt.Printf("错误: 密码加密失败 - %v\n", err)
		os.Exit(1)
	}

	if err := database.DB.Table("users").Where("id = ?", user.ID).Update("password", string(hashedPassword)).Error; err != nil {
		fmt.Printf("错误: 更新密码失败 - %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("成功: 用户 '%s' 的密码已重置\n", username)
	fmt.Printf("新密码: %s\n", newPassword)
}

func generateRandomPassword(length int) string {
	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%"
	result := make([]byte, length)
	for i := range result {
		result[i] = chars[i%len(chars)]
	}
	for i := len(result) - 1; i > 0; i-- {
		j := i % len(chars)
		result[i], result[j] = result[j], result[i]
	}
	return string(result)
}

func startServer() {
	config.Init()
	logger.Init()
	database.Init()

	os.MkdirAll("uploads", 0755)

	if config.GetString("app.env") == "production" {
		gin.SetMode(gin.ReleaseMode)
	}

	r := gin.Default()
	r.MaxMultipartMemory = 32 << 20

	r.Use(middleware.Logger())
	r.Use(middleware.Recovery())
	r.Use(middleware.Cors())

	r.Use(func(c *gin.Context) {
		fmt.Printf("全局中间件: %s %s\n", c.Request.Method, c.Request.URL.Path)
		c.Next()
	})

	r.Static("/uploads", "uploads")
	router.SetupRoutes(r)
	setupEmbeddedFrontend(r)

	port := config.GetString("app.port")
	if port == "" {
		port = "8080"
	}

	log.Printf("Server starting on port %s", port)
	if err := r.Run(":" + port); err != nil {
		log.Fatal("Failed to start server: ", err)
	}
}

func setupEmbeddedFrontend(r *gin.Engine) {
	distFS, err := fs.Sub(embeddedFiles, "embedded/dist")
	if err != nil {
		log.Printf("Warning: embedded dist not found, frontend will not be served")
		return
	}

	indexHTML, err := fs.ReadFile(distFS, "index.html")
	if err != nil {
		log.Printf("Warning: index.html not found in embedded dist")
		return
	}

	r.NoRoute(func(c *gin.Context) {
		if c.Request.Method == "GET" && !strings.HasPrefix(c.Request.URL.Path, "/api/") {
			serveIndexHTML(c, string(indexHTML))
			return
		}
		c.JSON(404, gin.H{"error": "not found"})
	})

	r.GET("/assets/*filepath", func(c *gin.Context) {
		c.FileFromFS(c.Request.URL.Path, http.FS(distFS))
	})
}

func serveIndexHTML(c *gin.Context, indexHTML string) {
	settingService := service.NewSettingService()
	settings, err := settingService.GetSettingsByCategory("basic")
	if err != nil {
		settings = make(map[string]interface{})
	}

	siteName := getSettingString(settings, "siteName", "微授权")
	siteDescription := getSettingString(settings, "siteDescription", "专业的应用验证平台")
	siteKeywords := getSettingString(settings, "siteKeywords", "验证平台,软件授权,卡密验证")
	logoLight := getSettingString(settings, "logoLight", "")
	logoDark := getSettingString(settings, "logoDark", "")
	favicon := getSettingString(settings, "favicon", "")

	html := indexHTML
	html = strings.ReplaceAll(html, "{{.SiteName}}", siteName)
	html = strings.ReplaceAll(html, "{{.SiteDescription}}", siteDescription)
	html = strings.ReplaceAll(html, "{{.SiteKeywords}}", siteKeywords)
	html = strings.ReplaceAll(html, "{{.LogoLight}}", logoLight)
	html = strings.ReplaceAll(html, "{{.LogoDark}}", logoDark)
	html = strings.ReplaceAll(html, "{{.Favicon}}", favicon)

	c.Data(200, "text/html; charset=utf-8", []byte(html))
}

func getSettingString(settings map[string]interface{}, key, defaultValue string) string {
	if val, ok := settings[key]; ok {
		if str, ok := val.(string); ok && str != "" {
			return str
		}
	}
	return defaultValue
}
