package main

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

// App 结构体定义
type App struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	FileName string `json:"fileName"`
	Date     string `json:"date"`
	FilePath string `json:"-"` // 内部使用，不序列化
}

// 全局变量
var (
	apps      []App
	appsMutex sync.RWMutex // 读写锁，提高并发性能
	filesDir  = "./files"
	jsonFile  = "./apps.json"
	port      = ":6902"
)

// 生成唯一文件名
func generateUniqueFileName(originalName string) string {
	// 获取文件扩展名
	ext := filepath.Ext(originalName)
	// 生成基于时间、随机数和原文件名的MD5哈希
	timestamp := time.Now().UnixNano()
	random := rand.Int63()
	hash := md5.Sum([]byte(fmt.Sprintf("%d%d%s", timestamp, random, originalName)))
	// 组合成新的唯一文件名
	return fmt.Sprintf("%s%s", hex.EncodeToString(hash[:]), ext)
}

// 加载apps数据
func loadApps() {
	appsMutex.Lock()
	defer appsMutex.Unlock()

	file, err := os.Open(jsonFile)
	if err != nil {
		// 如果文件不存在，初始化空切片
		apps = []App{}
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	if err := decoder.Decode(&apps); err != nil {
		apps = []App{}
	}
}

// 保存apps数据
func saveApps() error {
	appsMutex.RLock()
	defer appsMutex.RUnlock()

	file, err := os.Create(jsonFile)
	if err != nil {
		return fmt.Errorf("failed to create apps.json: %w", err)
	}
	defer file.Close()

	encoder := json.NewEncoder(file)
	encoder.SetIndent("", "  ")
	if err := encoder.Encode(apps); err != nil {
		return fmt.Errorf("failed to encode apps: %w", err)
	}

	return nil
}

func main() {
	// 初始化随机数生成器
	rand.Seed(time.Now().UnixNano())

	// 创建files目录
	if err := os.MkdirAll(filesDir, 0755); err != nil {
		panic(fmt.Sprintf("failed to create files directory: %v", err))
	}

	// 加载apps数据
	loadApps()

	// 创建Gin引擎
	// 生产环境中应该使用gin.ReleaseMode
	// gin.SetMode(gin.ReleaseMode)
	r := gin.Default()

	// 添加CORS中间件
	r.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	})

	// API路由
	api := r.Group("/api")
	{
		api.GET("/apps", getApps)
		api.POST("/apps", uploadApp)
		api.GET("/apps/:id", downloadApp)
	}

	// 启动服务器
	fmt.Printf("Server is running on http://localhost%s\n", port)
	if err := r.Run(port); err != nil {
		panic(fmt.Sprintf("failed to start server: %v", err))
	}
}

// 获取App列表
func getApps(c *gin.Context) {
	appsMutex.RLock()
	defer appsMutex.RUnlock()

	c.JSON(http.StatusOK, apps)
}

// 上传App
func uploadApp(c *gin.Context) {
	// 获取表单数据
	name := c.PostForm("name")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "App名称不能为空"})
		return
	}

	// 获取上传的文件
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "文件上传失败: " + err.Error()})
		return
	}
	defer file.Close()

	// 生成唯一ID和文件名
	id := fmt.Sprintf("%d", time.Now().UnixNano())
	originalFileName := header.Filename
	uniqueFileName := generateUniqueFileName(originalFileName)
	filePath := filepath.Join(filesDir, uniqueFileName)

	// 创建目标文件
	dst, err := os.Create(filePath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "文件保存失败: " + err.Error()})
		return
	}
	defer dst.Close()

	// 复制文件内容
	if _, err = io.Copy(dst, file); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "文件复制失败: " + err.Error()})
		return
	}

	// 添加到App列表
	newApp := App{
		ID:       id,
		Name:     name,
		FileName: originalFileName,
		FilePath: uniqueFileName,
		Date:     time.Now().Format("2006-01-02 15:04:05"),
	}

	appsMutex.Lock()
	apps = append(apps, newApp)
	appsMutex.Unlock()

	// 保存到文件
	if err := saveApps(); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "保存数据失败: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}

// 下载指定App
func downloadApp(c *gin.Context) {
	// 获取ID
	id := c.Param("id")

	// 查找App
	appsMutex.RLock()
	var targetApp *App
	for i := range apps {
		if apps[i].ID == id {
			targetApp = &apps[i]
			break
		}
	}
	appsMutex.RUnlock()

	if targetApp == nil {
		c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "App不存在"})
		return
	}

	// 构建文件路径
	filePath := filepath.Join(filesDir, targetApp.FilePath)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "文件不存在"})
		return
	}

	// 提供文件下载，设置原始文件名
	c.FileAttachment(filePath, targetApp.FileName)
}
