package extension

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

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

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

func SetupRoutes(r *gin.RouterGroup) {
	ext := r.Group("/ext")
	ext.Use(ExtensionAuthMiddleware())
	{
		// 用户相关
		ext.GET("/user/:userId", handleGetUser)
		ext.GET("/users", handleGetUsers)
		ext.POST("/user/:userId/recharge", handleRechargeUser)
		ext.POST("/user/:userId/deduct", handleDeductUser)

		// 用户变量相关
		ext.GET("/user/:userId/variables", handleGetUserVariables)
		ext.POST("/user/:userId/variables", handleUpdateUserVariables)

		// 卡密相关
		ext.GET("/cards", handleGetCards)
		ext.POST("/cards/generate", handleGenerateCards)
		ext.GET("/card/:cardId", handleGetCard)

		// 通知相关
		ext.POST("/notification", handleSendNotification)
		ext.POST("/notification/batch", handleSendBatchNotification)

		// 应用信息
		ext.GET("/app/info", handleGetAppInfo)
		ext.GET("/app/stats", handleGetAppStats)

		// 应用变量相关
		ext.GET("/app/variables", handleGetAppVariables)
		ext.POST("/app/variables", handleUpdateAppVariables)
	}
}

func ExtensionAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		accessKey := c.GetHeader("X-Access-Key")
		signature := c.GetHeader("X-Signature")
		timestamp := c.GetHeader("X-Timestamp")

		if accessKey == "" || signature == "" || timestamp == "" {
			response.Error(c, 401, "缺少认证信息")
			c.Abort()
			return
		}

		ts, err := strconv.ParseInt(timestamp, 10, 64)
		if err != nil {
			response.Error(c, 401, "时间戳格式错误")
			c.Abort()
			return
		}

		if time.Now().Unix()-ts > 300 {
			response.Error(c, 401, "请求已过期")
			c.Abort()
			return
		}

		var apiKey model.ExtensionAPIKey
		if err := database.DB.Where("access_key = ? AND status = ?", accessKey, "active").
			Preload("Application").First(&apiKey).Error; err != nil {
			response.Error(c, 401, "API密钥无效")
			c.Abort()
			return
		}

		if apiKey.ExpiresAt != nil && apiKey.ExpiresAt.Before(time.Now()) {
			response.Error(c, 401, "API密钥已过期")
			c.Abort()
			return
		}

		bodyBytes, _ := io.ReadAll(c.Request.Body)
		c.Set("requestBody", bodyBytes)
		c.Request.Body = io.NopCloser(strings.NewReader(string(bodyBytes)))

		stringToSign := fmt.Sprintf("%s%s%s%s", c.Request.Method, c.Request.URL.Path, timestamp, string(bodyBytes))
		expectedSignature := generateSignature(apiKey.SecretKey, stringToSign)

		if !hmac.Equal([]byte(signature), []byte(expectedSignature)) {
			response.Error(c, 401, "签名验证失败")
			c.Abort()
			return
		}

		c.Set("apiKey", apiKey)
		c.Set("applicationID", apiKey.ApplicationID)

		var app model.Application
		if err := database.DB.First(&app, apiKey.ApplicationID).Error; err == nil {
			c.Set("user_id", app.UserID)
			c.Set("app_id", apiKey.ApplicationID)

			var user model.User
			if err := database.DB.Preload("CurrentPackage").First(&user, app.UserID).Error; err == nil {
				if user.CurrentPackageID != nil {
					var permission model.PackagePermission
					if err := database.DB.Where("package_id = ?", user.CurrentPackageID).First(&permission).Error; err == nil {
						now := time.Now()
						if user.ApiCallsResetAt == nil || now.Sub(*user.ApiCallsResetAt) >= 24*time.Hour {
							user.ApiCallsUsed = 0
							user.ApiCallsResetAt = &now
							database.DB.Save(&user)
						}

						if user.ApiCallsUsed >= permission.MaxApiCalls {
							response.Error(c, 403, fmt.Sprintf("API调用次数已达上限（%d次/天），请升级套餐", permission.MaxApiCalls))
							c.Abort()
							return
						}
					}
				}
			}
		}

		now := time.Now()
		database.DB.Model(&apiKey).Update("last_used_at", now)

		c.Next()

		if _, exists := c.Get("app_id"); exists {
			if userID, exists := c.Get("user_id"); exists {
				var user model.User
				if err := database.DB.First(&user, userID).Error; err == nil {
					user.ApiCallsUsed++
					database.DB.Save(&user)
				}
			}
		}
	}
}

func generateSignature(secretKey, data string) string {
	h := hmac.New(sha256.New, []byte(secretKey))
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}

func handleGetUser(c *gin.Context) {
	appID := c.GetUint("applicationID")
	userID := c.Param("userId")

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

	response.Success(c, gin.H{
		"id":              user.ID,
		"username":        user.Username,
		"email":           user.Email,
		"status":          user.Status,
		"balance":         user.Balance,
		"expiry_at":       user.ExpiryAt,
		"lastLoginAt":     user.LastLoginAt,
		"lastHeartbeatAt": user.LastHeartbeatAt,
		"isTrialUser":     user.IsTrialUser,
		"createdAt":       user.CreatedAt,
	})
}

func handleGetUsers(c *gin.Context) {
	appID := c.GetUint("applicationID")
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
	status := c.Query("status")
	search := c.Query("search")

	var users []model.AppUser
	var total int64

	query := database.DB.Model(&model.AppUser{}).Where("application_id = ?", appID)

	if status != "" {
		query = query.Where("status = ?", status)
	}

	if search != "" {
		query = query.Where("username LIKE ? OR email LIKE ?", "%"+search+"%", "%"+search+"%")
	}

	query.Count(&total)

	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
		response.Error(c, 500, "获取用户列表失败")
		return
	}

	response.Success(c, gin.H{
		"users":      users,
		"total":      total,
		"page":       page,
		"page_size":  pageSize,
		"total_page": (total + int64(pageSize) - 1) / int64(pageSize),
	})
}

func handleRechargeUser(c *gin.Context) {
	appID := c.GetUint("applicationID")
	userID := c.Param("userId")

	var req struct {
		Amount      int    `json:"amount" binding:"required"`
		Type        string `json:"type" binding:"required"` // balance, days
		Description string `json:"description"`
	}

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

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

	var user model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", userID, appID).First(&user).Error; err != nil {
		service.LogVerification(c, &app.ID, nil, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 用户不存在 - %s", userID), "", fmt.Errorf("用户不存在"))
		response.Error(c, 404, "用户不存在")
		return
	}

	if user.Balance == -1 {
		service.LogVerification(c, &app.ID, &user.ID, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 用户已是永久会员 - %s", user.Username), "", fmt.Errorf("该用户为永久会员，无需充值"))
		response.Error(c, 400, "该用户为永久会员，无需充值")
		return
	}

	now := time.Now()

	switch req.Type {
	case "days":
		var baseTime time.Time
		if user.ExpiryAt != nil && user.ExpiryAt.After(now) {
			baseTime = *user.ExpiryAt
		} else {
			baseTime = now
		}
		duration := time.Duration(req.Amount) * 24 * time.Hour
		newExpiry := baseTime.Add(duration)
		user.ExpiryAt = &newExpiry
	case "balance":
		user.Balance += float64(req.Amount)
	default:
		service.LogVerification(c, &app.ID, &user.ID, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 类型无效 - %s", req.Type), "", fmt.Errorf("充值类型无效"))
		response.Error(c, 400, "充值类型无效，仅支持days或balance类型")
		return
	}

	if err := database.DB.Save(&user).Error; err != nil {
		service.LogVerification(c, &app.ID, &user.ID, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 保存失败 - %s", user.Username), "", err)
		response.Error(c, 500, "充值失败")
		return
	}

	record := model.RechargeRecord{
		UserID:      user.ID,
		OrderNo:     fmt.Sprintf("EXT%d%d", time.Now().Unix(), user.ID),
		Amount:      float64(req.Amount),
		Status:      "success",
		PaymentType: "extension_api",
		Remark:      req.Description,
	}
	database.DB.Create(&record)

	service.LogVerification(c, &app.ID, &user.ID, "extension_recharge", fmt.Sprintf("扩展API充值: 用户%s, 类型:%s, 数量:%d", user.Username, req.Type, req.Amount), "", nil)

	response.Success(c, gin.H{
		"message": "充值成功",
		"user":    user,
	})
}

func handleDeductUser(c *gin.Context) {
	appID := c.GetUint("applicationID")
	userID := c.Param("userId")

	var req struct {
		Amount      int    `json:"amount" binding:"required"`
		Type        string `json:"type" binding:"required"` // balance, days
		Description string `json:"description"`
	}

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

	var app model.Application
	database.DB.First(&app, appID)

	var user model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", userID, appID).First(&user).Error; err != nil {
		service.LogVerification(c, &app.ID, nil, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 用户不存在 - %s", userID), "", fmt.Errorf("用户不存在"))
		response.Error(c, 404, "用户不存在")
		return
	}

	if user.Balance == -1 {
		service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 用户已是永久会员 - %s", user.Username), "", fmt.Errorf("该用户为永久会员，无法扣除"))
		response.Error(c, 400, "该用户为永久会员，无法扣除")
		return
	}

	now := time.Now()

	switch req.Type {
	case "days":
		if user.ExpiryAt == nil || user.ExpiryAt.Before(now) {
			service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 用户订阅已过期 - %s", user.Username), "", fmt.Errorf("用户订阅已过期"))
			response.Error(c, 400, "用户订阅已过期")
			return
		}
		duration := time.Duration(req.Amount) * 24 * time.Hour
		newExpiry := user.ExpiryAt.Add(-duration)
		if newExpiry.Before(now) {
			newExpiry = now
		}
		user.ExpiryAt = &newExpiry
	case "balance":
		if user.Balance < float64(req.Amount) {
			service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 余额不足 - %s", user.Username), "", fmt.Errorf("余额不足"))
			response.Error(c, 400, "余额不足")
			return
		}
		user.Balance -= float64(req.Amount)
	default:
		service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 类型无效 - %s", req.Type), "", fmt.Errorf("扣除类型无效"))
		response.Error(c, 400, "扣除类型无效，仅支持days或balance类型")
		return
	}

	if err := database.DB.Save(&user).Error; err != nil {
		service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 保存失败 - %s", user.Username), "", err)
		response.Error(c, 500, "扣除失败")
		return
	}

	record := model.ConsumptionRecord{
		UserID:      user.ID,
		OrderNo:     fmt.Sprintf("EXT%d%d", time.Now().Unix(), user.ID),
		Type:        req.Type,
		Amount:      float64(req.Amount),
		Status:      "success",
		PaymentType: "extension_api",
		Remark:      req.Description,
	}
	database.DB.Create(&record)

	service.LogVerification(c, &app.ID, &user.ID, "extension_deduct", fmt.Sprintf("扩展API扣费: 用户%s, 类型:%s, 数量:%d", user.Username, req.Type, req.Amount), "", nil)

	response.Success(c, gin.H{
		"message": "扣除成功",
		"user":    user,
	})
}

func handleGetUserVariables(c *gin.Context) {
	appID := c.GetUint("applicationID")
	userID := c.Param("userId")

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

	var variables []model.CloudVariable
	if err := database.DB.Where("app_id = ?", appID).Find(&variables).Error; err != nil {
		response.Error(c, 500, "获取变量定义失败")
		return
	}

	var userVariables []model.UserVariable
	if err := database.DB.Where("user_id = ? AND app_id = ?", userID, appID).Find(&userVariables).Error; err != nil {
		response.Error(c, 500, "获取用户变量失败")
		return
	}

	userVarMap := make(map[string]string)
	for _, uv := range userVariables {
		userVarMap[uv.VarName] = uv.VarValue
	}

	result := make(map[string]interface{})
	for _, v := range variables {
		if v.Scope == "app" {
			result[v.Key] = gin.H{
				"value": v.DefaultValue,
				"scope": "app",
			}
		} else {
			value := v.DefaultValue
			if uv, ok := userVarMap[v.Key]; ok {
				value = uv
			}
			result[v.Key] = gin.H{
				"value": value,
				"scope": "user",
			}
		}
	}

	response.Success(c, result)
}

func handleUpdateUserVariables(c *gin.Context) {
	appID := c.GetUint("applicationID")
	userID := c.Param("userId")

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

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

	var variables []model.CloudVariable
	if err := database.DB.Where("app_id = ?", appID).Find(&variables).Error; err != nil {
		response.Error(c, 500, "获取变量定义失败")
		return
	}

	varMap := make(map[string]model.CloudVariable)
	for _, v := range variables {
		varMap[v.Key] = v
	}

	for key, value := range req.Variables {
		variable, exists := varMap[key]
		if !exists {
			continue
		}

		if variable.Scope == "app" {
			variable.DefaultValue = value
			database.DB.Save(&variable)
		} else {
			var userVar model.UserVariable
			if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, appID, key).First(&userVar).Error; err != nil {
				userVar = model.UserVariable{
					UserID:   user.ID,
					AppID:    appID,
					VarName:  key,
					VarValue: value,
					VarType:  variable.VarType,
				}
				database.DB.Create(&userVar)
			} else {
				userVar.VarValue = value
				database.DB.Save(&userVar)
			}
		}
	}

	response.Success(c, gin.H{
		"message": "更新成功",
	})
}

func handleGetAppVariables(c *gin.Context) {
	appID := c.GetUint("applicationID")

	var variables []model.CloudVariable
	if err := database.DB.Where("app_id = ? AND scope = ?", appID, "app").Find(&variables).Error; err != nil {
		response.Error(c, 500, "获取应用变量失败")
		return
	}

	result := make(map[string]string)
	for _, v := range variables {
		result[v.Key] = v.DefaultValue
	}

	response.Success(c, result)
}

func handleUpdateAppVariables(c *gin.Context) {
	appID := c.GetUint("applicationID")

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

	for key, value := range req.Variables {
		var variable model.CloudVariable
		if err := database.DB.Where("app_id = ? AND key = ? AND scope = ?", appID, key, "app").First(&variable).Error; err == nil {
			variable.DefaultValue = value
			database.DB.Save(&variable)
		}
	}

	response.Success(c, gin.H{
		"message": "更新成功",
	})
}

func handleGetCards(c *gin.Context) {
	appID := c.GetUint("applicationID")
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
	status := c.Query("status")
	cardTypeID := c.Query("card_type_id")

	var cards []model.Card
	var total int64

	query := database.DB.Model(&model.Card{}).Where("application_id = ?", appID)

	if status != "" {
		query = query.Where("status = ?", status)
	}

	if cardTypeID != "" {
		query = query.Where("card_type_id = ?", cardTypeID)
	}

	query.Count(&total)

	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&cards).Error; err != nil {
		response.Error(c, 500, "获取卡密列表失败")
		return
	}

	response.Success(c, gin.H{
		"cards":      cards,
		"total":      total,
		"page":       page,
		"page_size":  pageSize,
		"total_page": (total + int64(pageSize) - 1) / int64(pageSize),
	})
}

func handleGenerateCards(c *gin.Context) {
	appID := c.GetUint("applicationID")

	var req struct {
		CardTypeID uint `json:"card_type_id" binding:"required"`
		Count      int  `json:"count" binding:"required"`
	}

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

	var cardType model.CardType
	if err := database.DB.Where("id = ? AND application_id = ?", req.CardTypeID, appID).First(&cardType).Error; err != nil {
		response.Error(c, 404, "卡密类型不存在")
		return
	}

	cards := make([]model.Card, req.Count)
	for i := 0; i < req.Count; i++ {
		cardKey := generateCardKey()
		cards[i] = model.Card{
			ApplicationID: appID,
			CardTypeID:    req.CardTypeID,
			CardKey:       cardKey,
			Status:        "unused",
		}
	}

	if err := database.DB.Create(&cards).Error; err != nil {
		response.Error(c, 500, "生成卡密失败")
		return
	}

	response.Success(c, gin.H{
		"message": "生成成功",
		"count":   req.Count,
		"cards":   cards,
	})
}

func handleGetCard(c *gin.Context) {
	appID := c.GetUint("applicationID")
	cardID := c.Param("cardId")

	var card model.Card
	if err := database.DB.Where("id = ? AND application_id = ?", cardID, appID).First(&card).Error; err != nil {
		response.Error(c, 404, "卡密不存在")
		return
	}

	response.Success(c, card)
}

func handleSendNotification(c *gin.Context) {
	appID := c.GetUint("applicationID")

	var req struct {
		UserID  uint   `json:"user_id" binding:"required"`
		Title   string `json:"title" binding:"required"`
		Content string `json:"content" binding:"required"`
		Type    string `json:"type"`
	}

	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
	}

	notification := model.Announcement{
		ApplicationID: appID,
		Title:         req.Title,
		Content:       req.Content,
		Type:          req.Type,
		Status:        "active",
	}

	if err := database.DB.Create(&notification).Error; err != nil {
		response.Error(c, 500, "发送通知失败")
		return
	}

	response.Success(c, gin.H{
		"message":      "发送成功",
		"notification": notification,
	})
}

func handleSendBatchNotification(c *gin.Context) {
	appID := c.GetUint("applicationID")

	var req struct {
		Title   string `json:"title" binding:"required"`
		Content string `json:"content" binding:"required"`
		Type    string `json:"type"`
	}

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

	notification := model.Announcement{
		ApplicationID: appID,
		Title:         req.Title,
		Content:       req.Content,
		Type:          req.Type,
		Status:        "active",
	}

	if err := database.DB.Create(&notification).Error; err != nil {
		response.Error(c, 500, "发送通知失败")
		return
	}

	response.Success(c, gin.H{
		"message":      "发送成功",
		"notification": notification,
	})
}

func handleGetAppInfo(c *gin.Context) {
	appID := c.GetUint("applicationID")

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

	response.Success(c, gin.H{
		"id":            app.ID,
		"name":          app.Name,
		"description":   app.Description,
		"billing_type":  app.BillingType,
		"encrypt_type":  app.EncryptType,
		"bind_type":     app.BindType,
		"max_devices":   app.MaxDevices,
		"multi_open_mode": app.MultiOpenMode,
		"enable_trial":  app.EnableTrial,
		"trial_balance": app.TrialBalance,
		"status":        app.Status,
		"created_at":    app.CreatedAt,
	})
}

func handleGetAppStats(c *gin.Context) {
	appID := c.GetUint("applicationID")

	var userCount, activeUserCount, cardCount, usedCardCount int64

	database.DB.Model(&model.AppUser{}).Where("application_id = ?", appID).Count(&userCount)
	database.DB.Model(&model.AppUser{}).Where("application_id = ? AND status = ?", appID, "active").Count(&activeUserCount)
	database.DB.Model(&model.Card{}).Where("application_id = ?", appID).Count(&cardCount)
	database.DB.Model(&model.Card{}).Where("application_id = ? AND status = ?", appID, "used").Count(&usedCardCount)

	response.Success(c, gin.H{
		"user_count":        userCount,
		"active_user_count": activeUserCount,
		"card_count":        cardCount,
		"used_card_count":   usedCardCount,
	})
}

func generateCardKey() string {
	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, 16)
	for i := range b {
		b[i] = charset[i%len(charset)]
	}
	return string(b)
}
