package app

import (
	"fmt"
	"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 SetupPaymentRoutes(r *gin.RouterGroup) {
	r.POST("/recharge", handleAppRecharge)
	r.POST("/trial", handleAppTrial)
}

func handleAppRecharge(c *gin.Context) {
	appKey := c.Param("appKey")
	var app model.Application
	if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}

	if service.GetApplicationDisabledStatus(app.ID) {
		response.Error(c, 403, "该应用已被禁用")
		return
	}

	var req struct {
		Username string `json:"username"`
		CardKey  string `json:"card_key"`
		DeviceID string `json:"device_id"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if blocked, reason := checkRiskControl(c, app.ID, req.DeviceID, req.Username); blocked {
		response.Error(c, 403, reason)
		return
	}

	var card model.Card
	if err := database.DB.Preload("CardType").Where("card_key = ?", req.CardKey).First(&card).Error; err != nil {
		service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密不存在 - %s", req.CardKey), "", fmt.Errorf("卡密不存在"))
		response.Error(c, 404, "卡密不存在")
		return
	}

	fmt.Printf("[DEBUG] 卡密信息: ID=%d, CardKey=%s, Status=%s, CardTypeID=%d\n", card.ID, card.CardKey, card.Status, card.CardTypeID)
	fmt.Printf("[DEBUG] 卡类信息: ID=%d, Name=%s, Value=%f, Price=%f\n", card.CardType.ID, card.CardType.Name, card.CardType.Value, card.CardType.Price)

	if card.Status != "unused" {
		service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密已使用 - %s", req.CardKey), "", fmt.Errorf("卡密已使用"))
		response.Error(c, 400, "卡密已使用")
		return
	}

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

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

	fmt.Printf("[DEBUG] 充值前用户信息: ID=%d, Username=%s, Balance=%f, ExpiryAt=%v\n", user.ID, user.Username, user.Balance, user.ExpiryAt)

	tx := database.DB.Begin()

	card.Status = "used"
	card.AppUserID = &user.ID
	now := time.Now()
	card.UsedAt = &now

	if err := tx.Save(&card).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "充值失败")
		return
	}

	user.IsTrialUser = false

	if card.CardType.Value == -1 {
		if card.CardType.RechargeType == "subscription" {
			permanentExpiry := time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC)
			user.ExpiryAt = &permanentExpiry
			user.Balance = -1
		} else {
			user.Balance = -1
			user.ExpiryAt = nil
		}
	} else {
		switch card.CardType.RechargeType {
		case "subscription":
			var baseTime time.Time
			if user.ExpiryAt != nil && user.ExpiryAt.After(now) {
				baseTime = *user.ExpiryAt
			} else {
				baseTime = now
			}
			var duration time.Duration
			switch card.CardType.ValueUnit {
			case "minute":
				duration = time.Duration(card.CardType.Value) * time.Minute
			case "hour":
				duration = time.Duration(card.CardType.Value) * time.Hour
			case "day":
				duration = time.Duration(card.CardType.Value) * 24 * time.Hour
			case "month":
				duration = time.Duration(card.CardType.Value) * 30 * 24 * time.Hour
			case "year":
				duration = time.Duration(card.CardType.Value) * 365 * 24 * time.Hour
			default:
				duration = time.Duration(card.CardType.Value) * time.Second
			}
			newExpiry := baseTime.Add(duration)
			user.ExpiryAt = &newExpiry
		case "balance":
			fallthrough
		default:
			user.Balance += card.CardType.Value
		}
	}

	fmt.Printf("[DEBUG] 充值后用户信息: Balance=%f, ExpiryAt=%v (CardType.Value=%f, BillingType=%s)\n", user.Balance, user.ExpiryAt, card.CardType.Value, app.BillingType)

	if err := tx.Save(&user).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "更新用户信息失败")
		return
	}

	rechargeRecord := model.RechargeRecord{
		UserID:      user.ID,
		OrderNo:     generateOrderNo("R"),
		CardID:      &card.ID,
		CardCode:    card.CardKey,
		Amount:      card.CardType.Price,
		Status:      "success",
		PaymentType: "card",
		Remark:      "卡密充值 - " + card.CardType.Name,
	}

	if err := tx.Create(&rechargeRecord).Error; err != nil {
		tx.Rollback()
		response.Error(c, 500, "创建充值记录失败")
		return
	}

	if err := tx.Commit().Error; err != nil {
		response.Error(c, 500, "充值失败")
		return
	}

	service.LogVerification(c, &app.ID, &user.ID, "recharge", fmt.Sprintf("用户充值: %s, 卡密: %s, 金额: %.2f", user.Username, card.CardKey, card.CardType.Price), "", nil)

	response.SuccessWithMessage(c, "充值成功", gin.H{
		"message": "充值成功",
		"value":   card.CardType.Value,
	})
}

func handleAppTrial(c *gin.Context) {
	appKey := c.Param("appKey")
	var app model.Application
	if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
		response.Error(c, 404, "应用不存在")
		return
	}

	if service.GetApplicationDisabledStatus(app.ID) {
		response.Error(c, 403, "该应用已被禁用")
		return
	}

	if !app.EnableTrial {
		response.Error(c, 400, "该应用不支持试用")
		return
	}

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

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

	response.SuccessWithMessage(c, "试用成功", gin.H{
		"message":      "试用成功",
		"trial_balance": app.TrialBalance,
	})
}

func generateOrderNo(prefix string) string {
	return prefix + time.Now().Format("20060102150405") + randomString(6)
}

func randomString(length int) string {
	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := range b {
		b[i] = charset[time.Now().Nanosecond()%len(charset)]
		time.Sleep(1 * time.Nanosecond)
	}
	return string(b)
}
