package admin

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"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 SetupApplicationRoutes(r *gin.RouterGroup) {
	applications := r.Group("/applications")
	{
		applications.GET("", handleGetApplications)
		applications.POST("", handleCreateApplication)
		applications.PUT("/:id", handleUpdateApplication)
		applications.DELETE("/:id", handleDeleteApplication)
		applications.GET("/:id", handleGetApplication)
		applications.POST("/:id/icon", handleUploadIcon)
		applications.POST("/:id/upload", handleUploadVersionFile)
		applications.GET("/:id/versions", handleGetVersions)
		applications.POST("/:id/versions", handleCreateVersion)
		applications.GET("/:id/versions/:versionId", handleGetVersion)
		applications.PUT("/:id/versions/:versionId", handleUpdateVersion)
		applications.DELETE("/:id/versions/:versionId", handleDeleteVersion)
		applications.POST("/:id/versions/:versionId/publish", handlePublishVersion)
		applications.GET("/:id/announcements", handleGetApplicationAnnouncements)
		applications.POST("/:id/announcements", handleCreateAnnouncement)
		applications.PUT("/:id/announcements/:announcementId", handleUpdateAnnouncement)
		applications.DELETE("/:id/announcements/:announcementId", handleDeleteAnnouncement)
		applications.PUT("/:id/announcements/:announcementId/top", handleToggleAnnouncementTop)
		applications.POST("/:id/deduct", handleManualDeduct)
	}
}

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

	applications, err := service.GetApplicationsWithDisabledStatus(userID)
	if err != nil {
		response.Error(c, 500, "获取应用列表失败")
		return
	}

	fmt.Printf("找到 %d 个应用\n", len(applications))

	response.Success(c, gin.H{
		"applications": applications,
	})
}

func parseIntWithDefault(s string, defaultVal int) int {
	if s == "" {
		return defaultVal
	}
	val, err := strconv.Atoi(s)
	if err != nil {
		return defaultVal
	}
	return val
}

func parseFloatWithDefault(s string, defaultVal float64) float64 {
	if s == "" {
		return defaultVal
	}
	val, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return defaultVal
	}
	return val
}

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

	var req struct {
		Name                  string `form:"name" json:"name"`
		Description           string `form:"description" json:"description"`
		BillingType           string `form:"billing_type" json:"billing_type"`
		LoginPolicy           string `form:"login_policy" json:"login_policy"`
		EncryptType           string `form:"encrypt_type" json:"encrypt_type"`
		EncryptKey            string `form:"encrypt_key" json:"encrypt_key"`
		BindType              string `form:"bind_type" json:"bind_type"`
		MaxDevices            string `form:"max_devices" json:"max_devices"`
		ChangeLimit           string `form:"change_limit" json:"change_limit"`
		ChangeInterval        string `form:"change_interval" json:"change_interval"`
		ChangeExceedAction    string `form:"change_exceed_action" json:"change_exceed_action"`
		ChangeDeductAmount    string `form:"change_deduct_amount" json:"change_deduct_amount"`
		MultiOpenMode         string `form:"multi_open_mode" json:"multi_open_mode"`
		MaxInstances          string `form:"max_instances" json:"max_instances"`
		EnableTrial           string `form:"enable_trial" json:"enable_trial"`
		TrialBalance          string `form:"trial_balance" json:"trial_balance"`
		TrialDays             string `form:"trial_days" json:"trial_days"`
		EnableFreePeriod      string `form:"enable_free_period" json:"enable_free_period"`
		FreePeriodType        string `form:"free_period_type" json:"free_period_type"`
		FreePeriodStart       string `form:"free_period_start" json:"free_period_start"`
		FreePeriodEnd         string `form:"free_period_end" json:"free_period_end"`
		FreePeriodWeekdays    string `form:"free_period_weekdays" json:"free_period_weekdays"`
		FreePeriodStartTime   string `form:"free_period_start_time" json:"free_period_start_time"`
		FreePeriodEndTime     string `form:"free_period_end_time" json:"free_period_end_time"`
		HeartbeatInterval     string `form:"heartbeat_interval" json:"heartbeat_interval"`
		HeartbeatTimeout      string `form:"heartbeat_timeout" json:"heartbeat_timeout"`
		MaxAttempts           string `form:"max_attempts" json:"max_attempts"`
		LockDuration          string `form:"lock_duration" json:"lock_duration"`
		DeductionMode         string `form:"deduction_mode" json:"deduction_mode"`
		DeductionType         string `form:"deduction_type" json:"deduction_type"`
		DeductionInterval     string `form:"deduction_interval" json:"deduction_interval"`
		DeductionUnit         string `form:"deduction_unit" json:"deduction_unit"`
		DeductionAmount       string `form:"deduction_amount" json:"deduction_amount"`
		DeductionCycle        string `form:"deduction_cycle" json:"deduction_cycle"`
		AllowRegister         string `form:"allow_register" json:"allow_register"`
		EnableLoginVerify     string `form:"enable_login_verify" json:"enable_login_verify"`
		EnableRegisterVerify  string `form:"enable_register_verify" json:"enable_register_verify"`
		EnablePasswordReset   string `form:"enable_password_reset" json:"enable_password_reset"`
		PasswordResetMethod   string `form:"password_reset_method" json:"password_reset_method"`
		PasswordResetEmailID  uint   `form:"password_reset_email_id" json:"password_reset_email_id"`
		PasswordResetSmsID    uint   `form:"password_reset_sms_id" json:"password_reset_sms_id"`
		Status                string `form:"status" json:"status"`
	}
	if err := c.ShouldBind(&req); err != nil {
		response.Error(c, 400, "参数错误: "+err.Error())
		return
	}

	enableTrial := req.EnableTrial == "true"
	enableFreePeriod := req.EnableFreePeriod == "true"
	allowRegister := req.AllowRegister != "false"
	enableLoginVerify := req.EnableLoginVerify == "true"
	enableRegisterVerify := req.EnableRegisterVerify == "true"
	enablePasswordReset := req.EnablePasswordReset == "true"

	maxDevices := parseIntWithDefault(req.MaxDevices, 1)
	changeLimit := parseIntWithDefault(req.ChangeLimit, 3)
	changeInterval := parseIntWithDefault(req.ChangeInterval, 7)
	changeDeductAmount := parseFloatWithDefault(req.ChangeDeductAmount, 1)
	maxInstances := parseIntWithDefault(req.MaxInstances, 1)
	trialBalance := parseFloatWithDefault(req.TrialBalance, 0)
	trialDays := parseIntWithDefault(req.TrialDays, 0)
	heartbeatInterval := parseIntWithDefault(req.HeartbeatInterval, 60)
	heartbeatTimeout := parseIntWithDefault(req.HeartbeatTimeout, 300)
	maxAttempts := parseIntWithDefault(req.MaxAttempts, 5)
	lockDuration := parseIntWithDefault(req.LockDuration, 30)
	deductionInterval := parseIntWithDefault(req.DeductionInterval, 1)
	deductionAmount := parseFloatWithDefault(req.DeductionAmount, 1)

	appKey := generateAppKey()
	encryptKey := req.EncryptKey
	if encryptKey == "" {
		encryptKey = generateSecretKey()
	}

	encryptType := req.EncryptType
	if encryptType == "" {
		encryptType = "none"
	}

	loginPolicy := req.LoginPolicy
	if loginPolicy == "" {
		loginPolicy = "loose"
	}

	changeExceedAction := req.ChangeExceedAction
	if changeExceedAction == "" {
		changeExceedAction = "deny"
	}

	multiOpenMode := req.MultiOpenMode
	if multiOpenMode == "" {
		multiOpenMode = "forbidden"
	}

	deductionUnit := req.DeductionUnit
	if deductionUnit == "" && req.DeductionCycle != "" {
		deductionUnit = req.DeductionCycle
	}

	passwordResetMethod := req.PasswordResetMethod
	if passwordResetMethod == "" {
		passwordResetMethod = "none"
	}

	var passwordResetEmailID *uint
	if req.PasswordResetEmailID > 0 {
		passwordResetEmailID = &req.PasswordResetEmailID
	}

	var passwordResetSmsID *uint
	if req.PasswordResetSmsID > 0 {
		passwordResetSmsID = &req.PasswordResetSmsID
	}

	app := model.Application{
		UserID:                userID,
		Name:                  req.Name,
		Description:           req.Description,
		AppKey:                appKey,
		EncryptKey:            encryptKey,
		BillingType:           req.BillingType,
		LoginPolicy:           loginPolicy,
		EncryptType:           encryptType,
		BindType:              req.BindType,
		MaxDevices:            maxDevices,
		ChangeLimit:           changeLimit,
		ChangeInterval:        changeInterval,
		ChangeExceedAction:    changeExceedAction,
		ChangeDeductAmount:    changeDeductAmount,
		MultiOpenMode:         multiOpenMode,
		MaxInstances:          maxInstances,
		EnableTrial:           enableTrial,
		TrialBalance:          trialBalance,
		TrialDays:             trialDays,
		EnableFreePeriod:      enableFreePeriod,
		FreePeriodType:        req.FreePeriodType,
		FreePeriodStart:       req.FreePeriodStart,
		FreePeriodEnd:         req.FreePeriodEnd,
		FreePeriodWeekdays:    req.FreePeriodWeekdays,
		FreePeriodStartTime:   req.FreePeriodStartTime,
		FreePeriodEndTime:     req.FreePeriodEndTime,
		HeartbeatInterval:     heartbeatInterval,
		HeartbeatTimeout:      heartbeatTimeout,
		MaxAttempts:           maxAttempts,
		LockDuration:          lockDuration,
		DeductionMode:         req.DeductionMode,
		DeductionType:         req.DeductionType,
		DeductionInterval:     deductionInterval,
		DeductionUnit:         deductionUnit,
		DeductionAmount:       deductionAmount,
		AllowRegister:         allowRegister,
		EnableLoginVerify:     enableLoginVerify,
		EnableRegisterVerify:  enableRegisterVerify,
		EnablePasswordReset:   enablePasswordReset,
		PasswordResetMethod:   passwordResetMethod,
		PasswordResetEmailID:  passwordResetEmailID,
		PasswordResetSmsID:    passwordResetSmsID,
		Status:                "active",
	}

	if err := database.DB.Create(&app).Error; err != nil {
		fmt.Printf("创建应用失败: %v\n", err)
		response.Error(c, 500, "创建应用失败: "+err.Error())
		return
	}

	file, header, err := c.Request.FormFile("icon")
	if err == nil {
		defer file.Close()
		uploadDir := "./uploads/icons"
		if err := os.MkdirAll(uploadDir, 0755); err == nil {
			ext := filepath.Ext(header.Filename)
			filename := fmt.Sprintf("%d_%d%s", app.ID, time.Now().Unix(), ext)
			filePath := filepath.Join(uploadDir, filename)
			dst, err := os.Create(filePath)
			if err == nil {
				defer dst.Close()
				if _, err := io.Copy(dst, file); err == nil {
					app.IconURL = "/uploads/icons/" + filename
					database.DB.Model(&app).Update("icon_url", app.IconURL)
				}
			}
		}
	}

	service.LogOperationWithApp(c, &app.ID, "create", "application", &app.ID, fmt.Sprintf("创建应用: %s", app.Name), nil)

	response.Success(c, gin.H{
		"application": app,
	})
}

func generateAppKey() string {
	bytes := make([]byte, 16)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)
}

func generateSecretKey() string {
	bytes := make([]byte, 32)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)
}

func handleUpdateApplication(c *gin.Context) {
	userID := c.GetUint("user_id")
	var req struct {
		Name                  string  `form:"name" json:"name"`
		Description           string  `form:"description" json:"description"`
		BillingType           string  `form:"billing_type" json:"billing_type"`
		LoginPolicy           string  `form:"login_policy" json:"login_policy"`
		AllowRegister         bool    `form:"allow_register" json:"allow_register"`
		EnableLoginVerify     bool    `form:"enable_login_verify" json:"enable_login_verify"`
		EnableRegisterVerify  bool    `form:"enable_register_verify" json:"enable_register_verify"`
		VerifyMethod          string  `form:"verify_method" json:"verify_method"`
		EmailConfigID         *uint   `form:"email_config_id" json:"email_config_id"`
		SmsConfigID           *uint   `form:"sms_config_id" json:"sms_config_id"`
		EncryptType           string  `form:"encrypt_type" json:"encrypt_type"`
		EncryptKey            string  `form:"encrypt_key" json:"encrypt_key"`
		BindType              string  `form:"bind_type" json:"bind_type"`
		MaxDevices            int     `form:"max_devices" json:"max_devices"`
		ChangeLimit           int     `form:"change_limit" json:"change_limit"`
		ChangeInterval        int     `form:"change_interval" json:"change_interval"`
		ChangeExceedAction    string  `form:"change_exceed_action" json:"change_exceed_action"`
		ChangeDeductAmount    float64 `form:"change_deduct_amount" json:"change_deduct_amount"`
		MultiOpenMode         string  `form:"multi_open_mode" json:"multi_open_mode"`
		MaxInstances          int     `form:"max_instances" json:"max_instances"`
		EnableTrial           bool    `form:"enable_trial" json:"enable_trial"`
		TrialBalance          float64 `form:"trial_balance" json:"trial_balance"`
		TrialDays             int     `form:"trial_days" json:"trial_days"`
		EnableFreePeriod      bool    `form:"enable_free_period" json:"enable_free_period"`
		FreePeriodType        string  `form:"free_period_type" json:"free_period_type"`
		FreePeriodStart       string  `form:"free_period_start" json:"free_period_start"`
		FreePeriodEnd         string  `form:"free_period_end" json:"free_period_end"`
		FreePeriodWeekdays    string  `form:"free_period_weekdays" json:"free_period_weekdays"`
		FreePeriodStartTime   string  `form:"free_period_start_time" json:"free_period_start_time"`
		FreePeriodEndTime     string  `form:"free_period_end_time" json:"free_period_end_time"`
		HeartbeatInterval     int     `form:"heartbeat_interval" json:"heartbeat_interval"`
		HeartbeatTimeout      int     `form:"heartbeat_timeout" json:"heartbeat_timeout"`
		MaxAttempts           int     `form:"max_attempts" json:"max_attempts"`
		LockDuration          int     `form:"lock_duration" json:"lock_duration"`
		Status                string  `form:"status" json:"status"`
		DeductionMode         string  `form:"deduction_mode" json:"deduction_mode"`
		DeductionType         string  `form:"deduction_type" json:"deduction_type"`
		DeductionInterval     int     `form:"deduction_interval" json:"deduction_interval"`
		DeductionUnit         string  `form:"deduction_unit" json:"deduction_unit"`
		DeductionAmount       float64 `form:"deduction_amount" json:"deduction_amount"`
		EnablePasswordReset   bool    `form:"enable_password_reset" json:"enable_password_reset"`
		PasswordResetMethod   string  `form:"password_reset_method" json:"password_reset_method"`
		PasswordResetEmailID  *uint   `form:"password_reset_email_id" json:"password_reset_email_id"`
		PasswordResetSmsID    *uint   `form:"password_reset_sms_id" json:"password_reset_sms_id"`
	}

	contentType := c.GetHeader("Content-Type")
	var err error
	if contentType != "" && len(contentType) >= 19 && contentType[:19] == "multipart/form-data" {
		err = c.ShouldBind(&req)
	} else {
		err = c.ShouldBindJSON(&req)
	}
	if err != nil {
		response.Error(c, 400, "参数错误: "+err.Error())
		return
	}

	fmt.Printf("更新应用请求: EncryptType=%s, EncryptKey=%s\n", req.EncryptType, req.EncryptKey)

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

	fmt.Printf("更新应用前: ID=%d, EncryptType=%s, EncryptKey=%s\n", app.ID, app.EncryptType, app.EncryptKey)

	app.Name = req.Name
	app.Description = req.Description
	app.BillingType = req.BillingType
	app.LoginPolicy = req.LoginPolicy
	app.AllowRegister = req.AllowRegister
	app.EnableLoginVerify = req.EnableLoginVerify
	app.EnableRegisterVerify = req.EnableRegisterVerify
	app.VerifyMethod = req.VerifyMethod
	app.EmailConfigID = req.EmailConfigID
	app.SmsConfigID = req.SmsConfigID
	app.EncryptType = req.EncryptType
	if req.EncryptKey != "" {
		app.EncryptKey = req.EncryptKey
	}
	app.BindType = req.BindType
	app.MaxDevices = req.MaxDevices
	app.ChangeLimit = req.ChangeLimit
	app.ChangeInterval = req.ChangeInterval
	app.ChangeExceedAction = req.ChangeExceedAction
	app.ChangeDeductAmount = req.ChangeDeductAmount
	app.MultiOpenMode = req.MultiOpenMode
	app.MaxInstances = req.MaxInstances
	app.EnableTrial = req.EnableTrial
	app.TrialBalance = req.TrialBalance
	app.TrialDays = req.TrialDays
	app.EnableFreePeriod = req.EnableFreePeriod
	app.FreePeriodType = req.FreePeriodType
	app.FreePeriodStart = req.FreePeriodStart
	app.FreePeriodEnd = req.FreePeriodEnd
	app.FreePeriodWeekdays = req.FreePeriodWeekdays
	app.FreePeriodStartTime = req.FreePeriodStartTime
	app.FreePeriodEndTime = req.FreePeriodEndTime
	if req.HeartbeatInterval > 0 {
		app.HeartbeatInterval = req.HeartbeatInterval
	}
	if req.HeartbeatTimeout > 0 {
		app.HeartbeatTimeout = req.HeartbeatTimeout
	}
	if req.MaxAttempts > 0 {
		app.MaxAttempts = req.MaxAttempts
	}
	if req.LockDuration > 0 {
		app.LockDuration = req.LockDuration
	}
	app.Status = req.Status
	app.DeductionMode = req.DeductionMode
	app.DeductionType = req.DeductionType
	app.DeductionInterval = req.DeductionInterval
	app.DeductionUnit = req.DeductionUnit
	app.DeductionAmount = req.DeductionAmount
	app.EnablePasswordReset = req.EnablePasswordReset
	if req.PasswordResetMethod != "" {
		app.PasswordResetMethod = req.PasswordResetMethod
	}
	app.PasswordResetEmailID = req.PasswordResetEmailID
	app.PasswordResetSmsID = req.PasswordResetSmsID

	file, header, err := c.Request.FormFile("icon")
	if err == nil {
		defer file.Close()
		uploadDir := "./uploads/icons"
		if err := os.MkdirAll(uploadDir, 0755); err != nil {
			response.Error(c, 500, "创建上传目录失败")
			return
		}
		ext := filepath.Ext(header.Filename)
		filename := fmt.Sprintf("%d_%d%s", app.ID, time.Now().Unix(), ext)
		filePath := filepath.Join(uploadDir, filename)
		dst, err := os.Create(filePath)
		if err != nil {
			response.Error(c, 500, "保存文件失败")
			return
		}
		defer dst.Close()
		if _, err := io.Copy(dst, file); err != nil {
			response.Error(c, 500, "保存文件失败")
			return
		}
		app.IconURL = "/uploads/icons/" + filename
	}

	fmt.Printf("更新应用: ID=%d, EncryptType=%s, EncryptKey=%s\n", app.ID, app.EncryptType, app.EncryptKey)

	if err := database.DB.Save(&app).Error; err != nil {
		response.Error(c, 500, "更新应用失败")
		return
	}

	service.LogOperationWithApp(c, &app.ID, "update", "application", &app.ID, fmt.Sprintf("更新应用: %s", app.Name), nil)

	response.Success(c, app)
}

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

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

	appName := app.Name
	appID := app.ID

	tx := database.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	if err := tx.Where("id = ? AND user_id = ?", id, userID).Delete(&model.Application{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除应用失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.Version{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除版本失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.CardType{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除卡密类型失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.Card{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除卡密失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.Announcement{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除公告失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.AppUser{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除应用用户失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.AgentApplication{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除代理授权失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.Ticket{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除工单失败")
		return
	}

	if err := tx.Where("app_id = ?", id).Delete(&model.UserVariable{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除用户变量失败")
		return
	}

	if err := tx.Where("application_id = ?", id).Delete(&model.UserDevice{}).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "删除用户设备失败")
		return
	}

	if err := tx.Commit().Error; err != nil {
		response.Error(c, 500, "删除应用失败")
		return
	}

	service.LogOperation(c, "delete", "application", &appID, fmt.Sprintf("删除应用: %s", appName), nil)

	response.Success(c, nil)
}

func handleGetApplication(c *gin.Context) {
	userID := c.GetUint("user_id")
	id := c.Param("id")
	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", id, userID).First(&app).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}
	response.Success(c, gin.H{
		"application": app,
	})
}

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

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

	page := c.DefaultQuery("page", "1")
	pageSize := c.DefaultQuery("page_size", "10")

	var total int64
	database.DB.Model(&model.Announcement{}).Where("application_id = ?", appID).Count(&total)

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

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

	if err := database.DB.Where("application_id = ?", appID).Order("is_top DESC, created_at DESC").Limit(limit).Offset(offset).Find(&announcements).Error; err != nil {
		response.Error(c, 500, "获取公告列表失败")
		return
	}

	response.Success(c, gin.H{
		"announcements": announcements,
		"total":         total,
	})
}

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

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

	var req struct {
		Title   string `json:"title"`
		Content string `json:"content"`
		Type    string `json:"type"`
		Status  string `json:"status"`
		IsTop   bool   `json:"is_top"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	announcement := model.Announcement{
		ApplicationID: app.ID,
		Title:         req.Title,
		Content:       req.Content,
		Type:          req.Type,
		Status:        req.Status,
		IsTop:         req.IsTop,
	}

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

	response.Success(c, announcement)
}

func handleUpdateAnnouncement(c *gin.Context) {
	userID := c.GetUint("user_id")
	appID := c.Param("id")
	announcementID := c.Param("announcementId")

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

	var req struct {
		Title   string `json:"title"`
		Content string `json:"content"`
		Type    string `json:"type"`
		Status  string `json:"status"`
		IsTop   bool   `json:"is_top"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	var announcement model.Announcement
	if err := database.DB.Where("id = ? AND application_id = ?", announcementID, appID).First(&announcement).Error; err != nil {
		response.Error(c, 404, "公告不存在")
		return
	}

	announcement.Title = req.Title
	announcement.Content = req.Content
	announcement.Type = req.Type
	announcement.Status = req.Status
	announcement.IsTop = req.IsTop

	if err := database.DB.Save(&announcement).Error; err != nil {
		response.Error(c, 500, "更新公告失败")
		return
	}

	response.Success(c, announcement)
}

func handleDeleteAnnouncement(c *gin.Context) {
	userID := c.GetUint("user_id")
	appID := c.Param("id")
	announcementID := c.Param("announcementId")

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

	if err := database.DB.Where("id = ? AND application_id = ?", announcementID, appID).Delete(&model.Announcement{}).Error; err != nil {
		response.Error(c, 500, "删除公告失败")
		return
	}

	response.Success(c, nil)
}

func handleToggleAnnouncementTop(c *gin.Context) {
	userID := c.GetUint("user_id")
	appID := c.Param("id")
	announcementID := c.Param("announcementId")

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

	var announcement model.Announcement
	if err := database.DB.Where("id = ? AND application_id = ?", announcementID, appID).First(&announcement).Error; err != nil {
		response.Error(c, 404, "公告不存在")
		return
	}

	announcement.IsTop = !announcement.IsTop

	if err := database.DB.Save(&announcement).Error; err != nil {
		response.Error(c, 500, "更新公告失败")
		return
	}

	response.Success(c, announcement)
}

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

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

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

	filename := fmt.Sprintf("app_%d_%s", app.ID, file.Filename)
	if err := c.SaveUploadedFile(file, "uploads/"+filename); err != nil {
		response.Error(c, 500, "文件保存失败")
		return
	}

	app.IconURL = "/uploads/" + filename
	database.DB.Save(&app)

	response.Success(c, gin.H{
		"icon": app.IconURL,
	})
}

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

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

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

	fileSize := file.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
			}
		}
	}

	ext := filepath.Ext(file.Filename)
	timestamp := time.Now().Unix()
	filename := fmt.Sprintf("version_%d_%d%s", app.ID, timestamp, ext)
	dst := filepath.Join("uploads", filename)

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

	url := fmt.Sprintf("/uploads/%s", filename)
	absolutePath := filepath.Join(".", "uploads", filename)

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

		usage := model.StorageUsage{
			UserID:        userID,
			ApplicationID: &app.ID,
			ResourceType:  "version",
			ResourceID:    0,
			FileName:      file.Filename,
			FileSize:      info.Size(),
			Action:        "upload",
			CreatedAt:     time.Now(),
		}
		database.DB.Create(&usage)

		response.Success(c, gin.H{
			"url":  url,
			"size": info.Size(),
		})
	} else {
		response.Error(c, 500, "获取文件大小失败")
		return
	}
}

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

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

	var versions []model.Version
	if err := database.DB.Where("application_id = ?", appID).Find(&versions).Error; err != nil {
		response.Success(c, gin.H{
			"versions": []interface{}{},
		})
		return
	}

	response.Success(c, gin.H{
		"versions": versions,
	})
}

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

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

	var req struct {
		Version     string `json:"version"`
		Description string `json:"description"`
		FilePath    string `json:"file_path"`
		ForceUpdate bool   `json:"force_update"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	fmt.Printf("接收到的完整请求: Version=%s, Description=%s, FilePath=%s, ForceUpdate=%v\n",
		req.Version, req.Description, req.FilePath, req.ForceUpdate)

	finalFilePath := req.FilePath
	fileSize := int64(0)

	absoluteFilePath := filepath.Join(".", req.FilePath)
	fmt.Printf("请求的文件路径: %s, 绝对路径: %s\n", req.FilePath, absoluteFilePath)

	if info, err := os.Stat(absoluteFilePath); err == nil {
		fileSize = info.Size()
		fmt.Printf("文件大小: %d\n", fileSize)
	} else {
		fmt.Printf("获取文件大小失败: %v\n", err)
	}

	filePath := finalFilePath
	if !strings.HasPrefix(filePath, "/") {
		filePath = "/" + filepath.ToSlash(filePath)
	}

	version := model.Version{
		ApplicationID: app.ID,
		Version:       req.Version,
		Description:   req.Description,
		FilePath:      filePath,
		ForceUpdate:   req.ForceUpdate,
		Status:        "active",
		FileSize:      fileSize,
	}

	fmt.Printf("创建版本，文件大小: %d, 文件路径: %s\n", fileSize, filePath)

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

	response.Success(c, version)
}

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

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

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

	response.Success(c, version)
}

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

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

	var req struct {
		Version     string `json:"version"`
		Description string `json:"description"`
		FilePath    string `json:"file_path"`
		ForceUpdate bool   `json:"force_update"`
		Status      string `json:"status"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

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

	version.Version = req.Version
	version.Description = req.Description
	version.FilePath = req.FilePath
	version.ForceUpdate = req.ForceUpdate
	version.Status = req.Status

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

	response.Success(c, version)
}

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

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

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

	response.Success(c, nil)
}

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

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

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

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

	response.Success(c, version)
}

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

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

	if app.BillingType != "balance" {
		response.Error(c, 400, "只有余额模式的应用才支持手动扣费")
		return
	}

	if app.DeductionMode != "manual" {
		response.Error(c, 400, "该应用未开启手动扣费模式，请先在设置中修改扣费方式为手动扣费")
		return
	}

	var req struct {
		UserID      uint    `json:"user_id" binding:"required"`
		Amount      float64 `json:"amount" binding:"required,gt=0"`
		Description string  `json:"description"`
	}

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

	var user model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", req.UserID, appID).First(&user).Error; err != nil {
		response.Error(c, 404, "用户不存在")
		return
	}

	if user.Balance == -1 {
		response.Error(c, 400, "该用户为永久会员，无法扣费")
		return
	}

	if user.Balance < req.Amount {
		response.Error(c, 400, fmt.Sprintf("用户余额不足，当前余额: %.2f，需扣除: %.2f", user.Balance, req.Amount))
		return
	}

	user.Balance -= req.Amount
	if err := database.DB.Save(&user).Error; err != nil {
		response.Error(c, 500, "扣费失败")
		return
	}

	record := model.ConsumptionRecord{
		UserID:         user.ID,
		ApplicationID:  app.ID,
		Amount:         req.Amount,
		Type:           "manual_deduct",
		Description:    req.Description,
		BalanceAfter:   user.Balance,
	}

	if err := database.DB.Create(&record).Error; err != nil {
		fmt.Printf("创建消费记录失败: %v\n", err)
	}

	response.Success(c, gin.H{
		"user_id":        user.ID,
		"username":       user.Username,
		"amount":         req.Amount,
		"balance_before": user.Balance + req.Amount,
		"balance_after":  user.Balance,
		"description":    req.Description,
		"message":        "扣费成功",
	})
}
