package admin

import (
	"archive/zip"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/middleware"
	"verification-platform-backend/internal/model"
	"verification-platform-backend/internal/service"
	"verification-platform-backend/pkg/response"

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

func SetupVersionRoutes(r *gin.RouterGroup) {
	versions := r.Group("/versions")
	{
		versions.GET("", handleGetAllVersions)
		versions.GET("/:id", handleGetVersionByID)
		versions.POST("", handleCreateVersionGlobal)
		versions.PUT("/:id", handleUpdateVersionGlobal)
		versions.DELETE("/batch", handleBatchDeleteVersions)
		versions.POST("/upload-zip", handleUploadVersionZip)
		versions.POST("/:id/publish", handlePublishVersion)
		versions.POST("/:id/deprecate", handleDeprecateVersion)
		versions.POST("/:id/rollback", handleRollbackVersion)
	}
}

func handleGetAllVersions(c *gin.Context) {
	userID := c.GetUint("user_id")
	log.Printf("[DEBUG] handleGetAllVersions called, userID: %d\n", userID)

	page := c.DefaultQuery("page", "1")
	pageSize := c.DefaultQuery("page_size", "20")
	applicationIDFilter := c.Query("application_id")
	updateStrategyFilter := c.Query("update_strategy")
	updateTypeFilter := c.Query("update_type")
	updateMethodFilter := c.Query("update_method")
	searchFilter := c.Query("search")

	var total int64

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	log.Printf("[DEBUG] Found %d user apps\n", len(userApps))
	for i, app := range userApps {
		log.Printf("[DEBUG] App %d: ID=%d, Name=%s\n", i, app.ID, app.Name)
	}

	if len(userApps) == 0 {
		response.Success(c, gin.H{
			"versions": []interface{}{},
			"total":    0,
		})
		return
	}

	appIDs := make([]uint, len(userApps))
	appNameMap := make(map[uint]string)
	for i, app := range userApps {
		appIDs[i] = app.ID
		appNameMap[app.ID] = app.Name
	}

	log.Printf("[DEBUG] appNameMap: %v\n", appNameMap)

	countQuery := database.DB.Model(&model.Version{}).Where("application_id IN ?", appIDs)
	if applicationIDFilter != "" {
		countQuery = countQuery.Where("application_id = ?", applicationIDFilter)
	}
	if updateStrategyFilter != "" {
		countQuery = countQuery.Where("update_strategy = ?", updateStrategyFilter)
	}
	if updateTypeFilter != "" {
		countQuery = countQuery.Where("update_type = ?", updateTypeFilter)
	}
	if updateMethodFilter != "" {
		countQuery = countQuery.Where("update_method = ?", updateMethodFilter)
	}
	if searchFilter != "" {
		searchLower := strings.ToLower(searchFilter)
		countQuery = countQuery.Where("LOWER(version) LIKE ? OR LOWER(description) LIKE ?", "%"+searchLower+"%", "%"+searchLower+"%")
	}
	countQuery.Count(&total)

	var forcedCount int64
	database.DB.Model(&model.Version{}).Where("application_id IN ? AND update_strategy = ?", appIDs, "forced").Count(&forcedCount)

	// 计算总文件大小
	var totalSize int64
	sizeQuery := database.DB.Model(&model.Version{}).Where("application_id IN ?", appIDs)
	if applicationIDFilter != "" {
		sizeQuery = sizeQuery.Where("application_id = ?", applicationIDFilter)
	}
	if updateStrategyFilter != "" {
		sizeQuery = sizeQuery.Where("update_strategy = ?", updateStrategyFilter)
	}
	if updateTypeFilter != "" {
		sizeQuery = sizeQuery.Where("update_type = ?", updateTypeFilter)
	}
	if updateMethodFilter != "" {
		sizeQuery = sizeQuery.Where("update_method = ?", updateMethodFilter)
	}
	if searchFilter != "" {
		searchLower := strings.ToLower(searchFilter)
		sizeQuery = sizeQuery.Where("LOWER(version) LIKE ? OR LOWER(description) LIKE ?", "%"+searchLower+"%", "%"+searchLower+"%")
	}
	sizeQuery.Select("COALESCE(SUM(file_size), 0)").Scan(&totalSize)

	query := database.DB.Where("application_id IN ?", appIDs)
	if applicationIDFilter != "" {
		query = query.Where("application_id = ?", applicationIDFilter)
	}
	if updateStrategyFilter != "" {
		query = query.Where("update_strategy = ?", updateStrategyFilter)
	}
	if updateTypeFilter != "" {
		query = query.Where("update_type = ?", updateTypeFilter)
	}
	if updateMethodFilter != "" {
		query = query.Where("update_method = ?", updateMethodFilter)
	}
	if searchFilter != "" {
		searchLower := strings.ToLower(searchFilter)
		query = query.Where("LOWER(version) LIKE ? OR LOWER(description) LIKE ?", "%"+searchLower+"%", "%"+searchLower+"%")
	}

	var versions []model.Version
	offset := 0
	if pageInt, err := strconv.Atoi(page); err == nil && pageInt > 1 {
		offset = (pageInt - 1) * 20
	}

	limit := 20
	if pageSizeInt, err := strconv.Atoi(pageSize); err == nil && pageSizeInt > 0 {
		limit = pageSizeInt
	}

	if err := query.Order("created_at DESC").Limit(limit).Offset(offset).Find(&versions).Error; err != nil {
		response.Error(c, 500, "获取版本列表失败")
		return
	}

	log.Printf("[DEBUG] Found %d versions\n", len(versions))
	for i, v := range versions {
		log.Printf("[DEBUG] Version %d: ID=%d, ApplicationID=%d, Version=%s\n", i, v.ID, v.ApplicationID, v.Version)
	}

	versionIDs := make([]uint, len(versions))
	versionAppIDMap := make(map[uint]uint)
	for i, v := range versions {
		versionIDs[i] = v.ID
		versionAppIDMap[v.ID] = v.ApplicationID
	}

	var allVersionsForApps []model.Version
	database.DB.Where("application_id IN ?", appIDs).Select("id, application_id, update_strategy").Find(&allVersionsForApps)

	appForcedVersionIDs := make(map[uint][]uint)
	for _, v := range allVersionsForApps {
		if v.UpdateStrategy == "forced" {
			appForcedVersionIDs[v.ApplicationID] = append(appForcedVersionIDs[v.ApplicationID], v.ID)
		}
	}

	type VersionWithAppName struct {
		model.Version
		ApplicationName string `json:"application_name"`
			Status          string `json:"status"`
	}

	result := make([]VersionWithAppName, len(versions))
	for i, v := range versions {
		appName := appNameMap[v.ApplicationID]
		log.Printf("[DEBUG] Mapping version %d: ApplicationID=%d -> AppName=%s\n", i, v.ApplicationID, appName)

		// 使用数据库中的 publish_status 作为状态
		status := v.PublishStatus
		if status == "" {
			status = "draft"
		}

		result[i] = VersionWithAppName{
			Version:         v,
			ApplicationName: appName,
				Status:          status,
		}
	}

	response.Success(c, gin.H{
		"versions":     result,
		"total":        total,
		"forced_count": forcedCount,
		"total_size":   totalSize,
	})
}

func handleGetVersionByID(c *gin.Context) {
	userID := c.GetUint("user_id")
	versionID := c.Param("id")

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	appNameMap := make(map[uint]string)
	for i, app := range userApps {
		appIDs[i] = app.ID
		appNameMap[app.ID] = app.Name
	}

	var version model.Version
	if err := database.DB.Where("id = ? AND application_id IN ?", versionID, appIDs).Preload("Files").First(&version).Error; err != nil {
		response.Error(c, 404, "版本不存在")
		return
	}

	response.Success(c, gin.H{
		"id":                 version.ID,
		"application_id":     version.ApplicationID,
		"application_name":   appNameMap[version.ApplicationID],
		"version":            version.Version,
		"description":        version.Description,
		"file_path":          version.FilePath,
		"file_size":          version.FileSize,
		"file_hash":          version.FileHash,
		"update_strategy":    version.UpdateStrategy,
		"update_type":        version.UpdateType,
		"update_method":      version.UpdateMethod,
		"custom_download_url": version.CustomDownloadURL,
		"changelog":          version.Changelog,
		"status":             version.PublishStatus,
		"publish_status":     version.PublishStatus,
		"superseded_by":      version.SupersededBy,
		"published_at":       version.PublishedAt,
		"deprecated_at":      version.DeprecatedAt,
		"base_version_id":    version.BaseVersionID,
		"files":              version.Files,
		"created_at":         version.CreatedAt,
		"updated_at":         version.UpdatedAt,
	})
}

type CreateVersionRequest struct {
	ApplicationID      uint               `json:"application_id"`
	Version            string             `json:"version"`
	FilePath           string             `json:"file_path"`
	FileSize           int64              `json:"file_size"`
	FileHash           string             `json:"file_hash"`
	EntryFile          string             `json:"entry_file"`
	UpdateStrategy     string             `json:"update_strategy"`
	UpdateType         string             `json:"update_type"`
	UpdateMethod       string             `json:"update_method"`
	CustomDownloadURL  string             `json:"custom_download_url"`
	Description        string             `json:"description"`
	Changelog          string             `json:"changelog"`
	BaseVersionID      *uint              `json:"base_version_id"`
	Files              []VersionFileInput `json:"files"`
}

type VersionFileInput struct {
	FilePath   string `json:"file_path"`
	FileName   string `json:"file_name"`
	FileSize   int64  `json:"file_size"`
	FileHash   string `json:"file_hash"`
	FileType   string `json:"file_type"`
	IsRequired bool   `json:"is_required"`
}

func handleCreateVersionGlobal(c *gin.Context) {
	userID := c.GetUint("user_id")

	var req CreateVersionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", req.ApplicationID, userID).First(&app).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}

	if service.GetApplicationDisabledStatus(app.ID) {
		response.Error(c, 403, "应用已被禁用，无法创建版本")
		return
	}

	var existingVersion model.Version
	if err := database.DB.Where("application_id = ? AND version = ?", req.ApplicationID, req.Version).First(&existingVersion).Error; err == nil {
		response.Error(c, 400, "该版本号已存在")
		return
	}

	version := model.Version{
		ApplicationID:      req.ApplicationID,
		Version:            req.Version,
		FilePath:           req.FilePath,
		FileSize:           req.FileSize,
		FileHash:           req.FileHash,
		EntryFile:          req.EntryFile,
		UpdateStrategy:     req.UpdateStrategy,
		UpdateType:         req.UpdateType,
		UpdateMethod:       req.UpdateMethod,
		CustomDownloadURL:  req.CustomDownloadURL,
		Description:        req.Description,
		Changelog:          req.Changelog,
		PublishStatus:      "draft",
	}

	if version.UpdateStrategy == "" {
		version.UpdateStrategy = "optional"
	}
	if version.UpdateType == "" {
		version.UpdateType = "full"
	}
	if version.UpdateMethod == "" {
		version.UpdateMethod = "auto"
	}

	// 处理全量包和补丁包
	if version.UpdateType == "full" {
		// 全量包：full_package 就是自己
		version.FullPackagePath = version.FilePath
		version.FullPackageSize = version.FileSize
		version.FullPackageHash = version.FileHash

		// 尝试生成增量包（与前一个版本对比）
		var prevVersion model.Version
		if err := database.DB.Where("application_id = ? AND update_type = ?",
			req.ApplicationID, "full").
			Order("id DESC").First(&prevVersion).Error; err == nil {
			// 有前一个版本，生成增量包
			prevFullPackagePath := prevVersion.FullPackagePath
			if prevFullPackagePath == "" {
				prevFullPackagePath = prevVersion.FilePath
			}

			deltaPath, deltaSize, deltaHash, err := GenerateDeltaPackage(
				prevFullPackagePath,
				version.FilePath,
				req.ApplicationID,
			)
			if err != nil {
				log.Printf("[WARN] Failed to generate delta package: %v\n", err)
			} else if deltaPath != "" {
				version.DeltaPackagePath = deltaPath
				version.DeltaPackageSize = deltaSize
				version.DeltaPackageHash = deltaHash
				log.Printf("[INFO] Delta package created: %s, size: %d\n", deltaPath, deltaSize)
			}
		}
	} else if version.UpdateType == "patch" {
		// 补丁包：需要找到基础全量包并合并
		var baseVersion model.Version

		// 优先使用传入的 base_version_id
		if req.BaseVersionID != nil {
			if err := database.DB.Where("id = ? AND application_id = ? AND update_type = ?",
				*req.BaseVersionID, req.ApplicationID, "full").First(&baseVersion).Error; err != nil {
				response.Error(c, 400, "指定的基础版本不存在或不是全量版本")
				return
			}
		} else {
			// 未指定基础版本，使用最新的全量版本
			if err := database.DB.Where("application_id = ? AND update_type = ?", req.ApplicationID, "full").
				Order("id DESC").First(&baseVersion).Error; err != nil {
				response.Error(c, 400, "找不到基础全量包，无法创建补丁版本")
				return
			}
		}

		version.BaseVersionID = &baseVersion.ID

		// 获取基础版本的全量包路径，如果没有则使用 FilePath
		baseFullPackagePath := baseVersion.FullPackagePath
		if baseFullPackagePath == "" {
			baseFullPackagePath = baseVersion.FilePath
		}

		// 合并生成新的全量包
		fullPkgPath, fullPkgSize, fullPkgHash, err := MergePatchWithFullPackage(
			baseFullPackagePath,
			req.FilePath,
			req.ApplicationID,
		)
		if err != nil {
			log.Printf("[ERROR] Failed to merge patch with full package: %v\n", err)
			response.Error(c, 500, "合并补丁包失败: "+err.Error())
			return
		}

		version.FullPackagePath = fullPkgPath
		version.FullPackageSize = fullPkgSize
		version.FullPackageHash = fullPkgHash
	}

	if err := database.DB.Create(&version).Error; err != nil {
		response.Error(c, 500, "创建版本失败")
		return
	}

	// 保存文件列表
	if len(req.Files) > 0 {
		for i, f := range req.Files {
			versionFile := model.VersionFile{
				VersionID:  version.ID,
				FilePath:   f.FilePath,
				FileName:   f.FileName,
				FileSize:   f.FileSize,
				FileHash:   f.FileHash,
				FileType:   f.FileType,
				IsRequired: f.IsRequired,
				SortOrder:  i,
			}
			if err := database.DB.Create(&versionFile).Error; err != nil {
				log.Printf("[WARN] Failed to create version file record: %v\n", err)
			}
		}
	}

	userIDPtr := &userID
	versionIDPtr := &version.ID
	service.CreateLog(service.LogParams{
		UserID:     userIDPtr,
		LogType:    "version",
		Action:     "create",
		Resource:   "version",
		ResourceID: versionIDPtr,
		Details:    fmt.Sprintf("创建版本: %s (应用ID: %d)", version.Version, version.ApplicationID),
	})

	response.Success(c, gin.H{
		"id": version.ID,
	})
}

type UpdateVersionRequest struct {
	Version           string             `json:"version"`
	FilePath          string             `json:"file_path"`
	FileSize          int64              `json:"file_size"`
	FileHash          string             `json:"file_hash"`
	EntryFile         string             `json:"entry_file"`
	UpdateStrategy    string             `json:"update_strategy"`
	UpdateType        string             `json:"update_type"`
	UpdateMethod      string             `json:"update_method"`
	CustomDownloadURL string             `json:"custom_download_url"`
	Description       string             `json:"description"`
	Changelog         string             `json:"changelog"`
	BaseVersionID     *uint              `json:"base_version_id"`
	Files             []VersionFileInput `json:"files"`
}

func handleUpdateVersionGlobal(c *gin.Context) {
	userID := c.GetUint("user_id")
	versionID := c.Param("id")

	var req UpdateVersionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		log.Printf("[ERROR] ShouldBindJSON failed: %v\n", err)
		response.Error(c, 400, "参数错误")
		return
	}

	log.Printf("[DEBUG] UpdateVersionRequest parsed: %+v\n", req)

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	for i, app := range userApps {
		appIDs[i] = app.ID
	}

	var version model.Version
	if err := database.DB.Where("id = ? AND application_id IN ?", versionID, appIDs).First(&version).Error; err != nil {
		response.Error(c, 404, "版本不存在")
		return
	}

	if req.Version != "" && req.Version != version.Version {
		var existingVersion model.Version
		if err := database.DB.Where("application_id = ? AND version = ? AND id != ?", version.ApplicationID, req.Version, version.ID).First(&existingVersion).Error; err == nil {
			response.Error(c, 400, "该版本号已存在")
			return
		}
	}

	log.Printf("[DEBUG] handleUpdateVersionGlobal versionID=%s, req: version=%s, update_strategy=%s, update_type=%s, update_method=%s, description=%s\n",
		versionID, req.Version, req.UpdateStrategy, req.UpdateType, req.UpdateMethod, req.Description)

	updates := map[string]interface{}{}
	if req.Version != "" {
		updates["version"] = req.Version
	}
	if req.FilePath != "" {
		updates["file_path"] = req.FilePath
	}
	if req.FileSize > 0 {
		updates["file_size"] = req.FileSize
	}
	if req.FileHash != "" {
		updates["file_hash"] = req.FileHash
	}
	updates["entry_file"] = req.EntryFile
	if req.UpdateStrategy != "" {
		updates["update_strategy"] = req.UpdateStrategy
	}
	if req.UpdateType != "" {
		updates["update_type"] = req.UpdateType
	}
	if req.UpdateMethod != "" {
		updates["update_method"] = req.UpdateMethod
	}
	updates["custom_download_url"] = req.CustomDownloadURL
	if req.Description != "" {
		updates["description"] = req.Description
	}
	if req.Changelog != "" {
		updates["changelog"] = req.Changelog
	}

	log.Printf("[DEBUG] Updates map: %+v\n", updates)

	// 如果文件被更新，删除旧文件
	if req.FilePath != "" && req.FilePath != version.FilePath {
		oldFilePath := filepath.Join(".", version.FilePath)
		if _, err := os.Stat(oldFilePath); err == nil {
			if err := os.Remove(oldFilePath); err != nil {
				log.Printf("[WARN] Failed to remove old file %s: %v\n", oldFilePath, err)
			} else {
				log.Printf("[INFO] Removed old file: %s\n", oldFilePath)
			}
		}

		// 如果是补丁包，需要重新合并生成全量包
		updateType := version.UpdateType
		if req.UpdateType != "" {
			updateType = req.UpdateType
		}
		if updateType == "patch" && version.BaseVersionID != nil {
			var baseVersion model.Version
			if err := database.DB.First(&baseVersion, *version.BaseVersionID).Error; err == nil {
				baseFullPackagePath := baseVersion.FullPackagePath
				if baseFullPackagePath == "" {
					baseFullPackagePath = baseVersion.FilePath
				}

				fullPkgPath, fullPkgSize, fullPkgHash, err := MergePatchWithFullPackage(
					baseFullPackagePath,
					req.FilePath,
					version.ApplicationID,
				)
				if err != nil {
					log.Printf("[ERROR] Failed to merge patch with full package: %v\n", err)
					response.Error(c, 500, "合并补丁包失败: "+err.Error())
					return
				}

				updates["full_package_path"] = fullPkgPath
				updates["full_package_size"] = fullPkgSize
				updates["full_package_hash"] = fullPkgHash
				log.Printf("[INFO] Updated full package: %s, size: %d\n", fullPkgPath, fullPkgSize)
			}
		}
	}

	if len(updates) == 0 {
		response.Success(c, nil)
		return
	}

	result := database.DB.Model(&model.Version{}).Where("id = ?", versionID).Updates(updates)
	if result.Error != nil {
		log.Printf("[ERROR] Updates failed: %v\n", result.Error)
		response.Error(c, 500, "更新版本失败")
		return
	}

	log.Printf("[DEBUG] Updates rows affected: %d\n", result.RowsAffected)
	if result.RowsAffected == 0 {
		response.Error(c, 500, "更新未生效，请重试")
		return
	}

	// 更新文件列表
	if len(req.Files) > 0 {
		// 删除旧的文件记录
		database.DB.Where("version_id = ?", version.ID).Delete(&model.VersionFile{})
		// 创建新的文件记录
		for i, f := range req.Files {
			versionFile := model.VersionFile{
				VersionID:  version.ID,
				FilePath:   f.FilePath,
				FileName:   f.FileName,
				FileSize:   f.FileSize,
				FileHash:   f.FileHash,
				FileType:   f.FileType,
				IsRequired: f.IsRequired,
				SortOrder:  i,
			}
			if err := database.DB.Create(&versionFile).Error; err != nil {
				log.Printf("[WARN] Failed to create version file record: %v\n", err)
			}
		}
	}

	userIDPtr := &userID
	versionIDPtr := &version.ID
	service.CreateLog(service.LogParams{
		UserID:     userIDPtr,
		LogType:    "version",
		Action:     "update",
		Resource:   "version",
		ResourceID: versionIDPtr,
		Details:    fmt.Sprintf("更新版本: %s (应用ID: %d)", version.Version, version.ApplicationID),
	})

	response.Success(c, nil)
}

func handleBatchDeleteVersions(c *gin.Context) {
	userID := c.GetUint("user_id")

	var req struct {
		IDs []uint `json:"ids"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if len(req.IDs) == 0 {
		response.Error(c, 400, "请选择要删除的版本")
		return
	}

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	for i, app := range userApps {
		appIDs[i] = app.ID
	}

	var versions []model.Version
	if err := database.DB.Where("id IN ? AND application_id IN ?", req.IDs, appIDs).Find(&versions).Error; err != nil {
		response.Error(c, 500, "获取版本失败")
		return
	}

	for _, version := range versions {
		for _, app := range userApps {
			if app.ID == version.ApplicationID && service.GetApplicationDisabledStatus(app.ID) {
				response.Error(c, 403, fmt.Sprintf("应用 %s 已被禁用，无法删除其版本", app.Name))
				return
			}
		}
	}

	// 检查是否有其他补丁包依赖这些版本
	var dependentPatches []model.Version
	if err := database.DB.Where("base_version_id IN ?", req.IDs).Find(&dependentPatches).Error; err != nil {
		response.Error(c, 500, "检查依赖关系失败")
		return
	}
	if len(dependentPatches) > 0 {
		dependentIDs := make([]string, len(dependentPatches))
		for i, p := range dependentPatches {
			dependentIDs[i] = fmt.Sprintf("v%d.%s", p.ID, p.Version)
		}
		response.Error(c, 400, fmt.Sprintf("以下补丁包依赖所选版本，无法删除: %s", strings.Join(dependentIDs, ", ")))
		return
	}

	if err := database.DB.Where("id IN ? AND application_id IN ?", req.IDs, appIDs).Delete(&model.Version{}).Error; err != nil {
		response.Error(c, 500, "批量删除版本失败")
		return
	}

	response.Success(c, nil)
}

type UploadVersionZipResponse struct {
	FilePath string                `json:"file_path"`
	FileSize int64                 `json:"file_size"`
	FileHash string                `json:"file_hash"`
	Files    []VersionFileInfo     `json:"files"`
}

type VersionFileInfo struct {
	FilePath string `json:"file_path"`
	FileName string `json:"file_name"`
	FileSize int64  `json:"file_size"`
	FileHash string `json:"file_hash"`
	FileType string `json:"file_type"`
}

func handleUploadVersionZip(c *gin.Context) {
	userID := c.GetUint("user_id")

	file, header, err := c.Request.FormFile("file")
	if err != nil {
		response.Error(c, 400, "请上传ZIP文件")
		return
	}
	defer file.Close()

	if !strings.HasSuffix(strings.ToLower(header.Filename), ".zip") {
		response.Error(c, 400, "只支持ZIP格式文件")
		return
	}

	fileSize := header.Size

	var user model.User
	if err := database.DB.First(&user, userID).Error; err != nil {
		response.Error(c, 500, "获取用户信息失败")
		return
	}

	if user.CurrentPackageID != nil {
		var permission model.PackagePermission
		if err := database.DB.Where("package_id = ?", user.CurrentPackageID).First(&permission).Error; err == nil {
			maxStorageBytes := int64(permission.MaxStorage) * 1024 * 1024
			if user.StorageUsed+fileSize > maxStorageBytes {
				usedMB := float64(user.StorageUsed) / 1024 / 1024
				maxMB := float64(permission.MaxStorage)
				response.Error(c, 403, fmt.Sprintf("存储空间不足，已使用 %.2f MB / %.2f MB", usedMB, maxMB))
				return
			}
		}
	}

	timestamp := time.Now().Unix()
	filename := fmt.Sprintf("version_%d_%d.zip", userID, timestamp)
	dst := filepath.Join("uploads", "versions", filename)

	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		response.Error(c, 500, "创建目录失败")
		return
	}

	dstFile, err := os.Create(dst)
	if err != nil {
		response.Error(c, 500, "创建文件失败")
		return
	}
	defer dstFile.Close()

	if _, err := io.Copy(dstFile, file); err != nil {
		response.Error(c, 500, "保存文件失败")
		return
	}

	zipHash, err := calculateFileHash(dst)
	if err != nil {
		os.Remove(dst)
		response.Error(c, 500, "计算文件哈希失败")
		return
	}

	files, err := parseZipFile(dst)
	if err != nil {
		os.Remove(dst)
		response.Error(c, 500, fmt.Sprintf("解析ZIP文件失败: %v", err))
		return
	}

	if err := middleware.UpdateStorageUsed(userID, fileSize, "upload"); err != nil {
		log.Printf("更新存储使用量失败: %v\n", err)
	}

	usage := model.StorageUsage{
		UserID:       userID,
		ResourceType: "version",
		ResourceID:   0,
		FileName:     header.Filename,
		FileSize:     fileSize,
		Action:       "upload",
		CreatedAt:    time.Now(),
	}
	database.DB.Create(&usage)

	response.Success(c, UploadVersionZipResponse{
		FilePath: fmt.Sprintf("/uploads/versions/%s", filename),
		FileSize: fileSize,
		FileHash: zipHash,
		Files:    files,
	})
}

func calculateFileHash(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

func parseZipFile(zipPath string) ([]VersionFileInfo, error) {
	reader, err := zip.OpenReader(zipPath)
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	var files []VersionFileInfo

	for _, f := range reader.File {
		if f.FileInfo().IsDir() {
			continue
		}

		rc, err := f.Open()
		if err != nil {
			continue
		}

		hash := sha256.New()
		if _, err := io.Copy(hash, rc); err != nil {
			rc.Close()
			continue
		}
		rc.Close()

		fileHash := hex.EncodeToString(hash.Sum(nil))
		fileType := getFileType(f.Name)

		files = append(files, VersionFileInfo{
			FilePath: f.Name,
			FileName: filepath.Base(f.Name),
			FileSize: int64(f.UncompressedSize64),
			FileHash: fileHash,
			FileType: fileType,
		})
	}

	return files, nil
}

func getFileType(filename string) string {
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".exe", ".dll", ".so", ".dylib", ".app":
		return "executable"
	case ".json", ".xml", ".yaml", ".yml", ".ini", ".conf", ".cfg":
		return "config"
	case ".txt", ".md", ".log":
		return "text"
	case ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".svg":
		return "image"
	case ".mp3", ".wav", ".ogg", ".flac":
		return "audio"
	case ".mp4", ".avi", ".mkv", ".mov", ".wmv":
		return "video"
	case ".db", ".sqlite", ".sqlite3":
		return "database"
	default:
		return "resource"
	}
}

func handlePublishVersion(c *gin.Context) {
	userID := c.GetUint("user_id")
	versionID := c.Param("id")

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	for i, app := range userApps {
		appIDs[i] = app.ID
	}

	var version model.Version
	if err := database.DB.Where("id = ? AND application_id IN ?", versionID, appIDs).First(&version).Error; err != nil {
		response.Error(c, 404, "版本不存在")
		return
	}

	if version.PublishStatus != "draft" && version.PublishStatus != "deprecated" {
		response.Error(c, 400, "只能发布草稿或已废弃的版本")
		return
	}

	now := time.Now()
	version.PublishStatus = "published"
	version.PublishedAt = &now

	if err := database.DB.Save(&version).Error; err != nil {
		response.Error(c, 500, "发布版本失败")
		return
	}

	// 如果是强制更新，标记旧版本为 superseded
	if version.UpdateStrategy == "forced" {
		database.DB.Model(&model.Version{}).
			Where("application_id = ? AND id < ? AND publish_status = ?", version.ApplicationID, version.ID, "published").
			Updates(map[string]interface{}{
				"publish_status": "superseded",
				"superseded_by":  version.ID,
				"deprecated_at":  now,
			})
	}

	userIDPtr := &userID
	versionIDPtr := &version.ID
	service.CreateLog(service.LogParams{
		UserID:     userIDPtr,
		LogType:    "version",
		Action:     "publish",
		Resource:   "version",
		ResourceID: versionIDPtr,
		Details:    fmt.Sprintf("发布版本: %s (应用ID: %d)", version.Version, version.ApplicationID),
	})

	response.Success(c, gin.H{
		"id":             version.ID,
		"publish_status": version.PublishStatus,
		"published_at":   version.PublishedAt,
	})
}

func handleDeprecateVersion(c *gin.Context) {
	userID := c.GetUint("user_id")
	versionID := c.Param("id")

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	for i, app := range userApps {
		appIDs[i] = app.ID
	}

	var version model.Version
	if err := database.DB.Where("id = ? AND application_id IN ?", versionID, appIDs).First(&version).Error; err != nil {
		response.Error(c, 404, "版本不存在")
		return
	}

	if version.PublishStatus != "published" {
		response.Error(c, 400, "只能废弃已发布的版本")
		return
	}

	now := time.Now()
	version.PublishStatus = "deprecated"
	version.DeprecatedAt = &now

	if err := database.DB.Save(&version).Error; err != nil {
		response.Error(c, 500, "废弃版本失败")
		return
	}

	// 如果有被该版本取代的版本，恢复它们为 published
	database.DB.Model(&model.Version{}).
		Where("superseded_by = ?", version.ID).
		Updates(map[string]interface{}{
			"publish_status": "published",
			"superseded_by":  nil,
			"deprecated_at":  nil,
		})

	userIDPtr := &userID
	versionIDPtr := &version.ID
	service.CreateLog(service.LogParams{
		UserID:     userIDPtr,
		LogType:    "version",
		Action:     "deprecate",
		Resource:   "version",
		ResourceID: versionIDPtr,
		Details:    fmt.Sprintf("废弃版本: %s (应用ID: %d)", version.Version, version.ApplicationID),
	})

	response.Success(c, gin.H{
		"id":             version.ID,
		"publish_status": version.PublishStatus,
		"deprecated_at":  version.DeprecatedAt,
	})
}

func handleRollbackVersion(c *gin.Context) {
	userID := c.GetUint("user_id")
	versionID := c.Param("id")

	var userApps []model.Application
	if err := database.DB.Where("user_id = ?", userID).Find(&userApps).Error; err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	appIDs := make([]uint, len(userApps))
	for i, app := range userApps {
		appIDs[i] = app.ID
	}

	var version model.Version
	if err := database.DB.Where("id = ? AND application_id IN ?", versionID, appIDs).First(&version).Error; err != nil {
		response.Error(c, 404, "版本不存在")
		return
	}

	// 只能回滚 superseded 状态的版本
	if version.PublishStatus != "superseded" {
		response.Error(c, 400, "只能回滚已被取代的版本")
		return
	}

	now := time.Now()
	version.PublishStatus = "published"
	version.SupersededBy = nil
	version.DeprecatedAt = nil

	if err := database.DB.Save(&version).Error; err != nil {
		response.Error(c, 500, "回滚版本失败")
		return
	}

	// 找到当前发布的版本，将其改为 superseded（如果有的话）
	var currentPublished model.Version
	err := database.DB.Where("application_id = ? AND publish_status = ? AND id != ?",
		version.ApplicationID, "published", version.ID).
		Order("id DESC").First(&currentPublished).Error
	if err == nil {
		currentPublished.PublishStatus = "superseded"
		currentPublished.SupersededBy = &version.ID
		currentPublished.DeprecatedAt = &now
		database.DB.Save(&currentPublished)
	}

	userIDPtr := &userID
	versionIDPtr := &version.ID
	service.CreateLog(service.LogParams{
		UserID:     userIDPtr,
		LogType:    "version",
		Action:     "rollback",
		Resource:   "version",
		ResourceID: versionIDPtr,
		Details:    fmt.Sprintf("回滚版本: %s (应用ID: %d)", version.Version, version.ApplicationID),
	})

	response.Success(c, gin.H{
		"id":             version.ID,
		"publish_status": version.PublishStatus,
	})
}
