package admin

import (
	"log"
	"strings"
	"time"
	"unicode"

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

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

func normalizeKey(name string) string {
	key := strings.ToLower(strings.TrimSpace(name))
	key = strings.Map(func(r rune) rune {
		if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' {
			return r
		}
		return '_'
	}, key)
	return key
}

func validateDynamicCode(code string) error {
	vm := goja.New()
	vm.Set("params", vm.NewObject())
	vm.Set("user", vm.NewObject())
	vm.Set("app", vm.NewObject())
	wrappedCode := "(function() { " + code + " })()"
	_, err := vm.RunString(wrappedCode)
	if err != nil {
		errStr := err.Error()
		if strings.Contains(errStr, "ReferenceError") || strings.Contains(errStr, "is not defined") {
			return nil
		}
		return err
	}
	return nil
}

func SetupDynamicRoutes(r *gin.RouterGroup) {
	dynamicCodes := r.Group("/dynamic-codes")
	{
		dynamicCodes.GET("", handleListDynamicCodes)
		dynamicCodes.GET("/:id", handleGetDynamicCode)
		dynamicCodes.POST("", handleCreateDynamicCode)
		dynamicCodes.PUT("/:id", handleUpdateDynamicCode)
		dynamicCodes.DELETE("/:id", handleDeleteDynamicCode)
		dynamicCodes.PUT("/:id/status", handleUpdateDynamicCodeStatus)
		dynamicCodes.DELETE("/batch", handleBatchDeleteDynamicCodes)
		dynamicCodes.PUT("/batch/status", handleBatchUpdateDynamicCodeStatus)
	}

	riskControl := r.Group("/risk-control")
	{
		riskControl.GET("/rules", handleGetRiskControlRules)
		riskControl.POST("/rules", handleCreateRiskControlRule)
		riskControl.PUT("/rules/:id", handleUpdateRiskControlRule)
		riskControl.DELETE("/rules/:id", handleDeleteRiskControlRule)
		riskControl.PUT("/rules/:id/status", handleUpdateRiskControlRuleStatus)
		riskControl.DELETE("/rules/batch", handleBatchDeleteRiskControlRules)
		riskControl.PUT("/rules/batch/status", handleBatchUpdateRiskControlRuleStatus)
	}
}

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	var dynamicCodes []model.DynamicCode
	if err := database.DB.Preload("Application").Preload("Creator").Where("application_id IN ?", applicationIDs).Find(&dynamicCodes).Error; err != nil {
		response.Error(c, 500, "获取动态代码列表失败")
		return

	}

	type DynamicCodeResponse struct {
		ID              uint   `json:"id"`
		Name            string `json:"name"`
		Code            string `json:"code"`
		Description     string `json:"description"`
		ApplicationID   uint   `json:"application_id"`
		ApplicationName string `json:"application_name"`
		Enabled         bool   `json:"enabled"`
		CreatedAt       string `json:"created_at"`
		UpdatedAt       string `json:"updated_at"`
		Creator         *struct {
			ID       uint   `json:"id"`
			Username string `json:"username"`
		} `json:"creator,omitempty"`
	}

	var result []DynamicCodeResponse
	for _, dc := range dynamicCodes {
		var creator *struct {
			ID       uint   `json:"id"`
			Username string `json:"username"`
		}
		if dc.UserID != nil && dc.Creator.ID != 0 {
			creator = &struct {
				ID       uint   `json:"id"`
				Username string `json:"username"`
			}{
				ID:       dc.Creator.ID,
				Username: dc.Creator.Username,
			}
		}

		result = append(result, DynamicCodeResponse{
			ID:              dc.ID,
			Name:            dc.Name,
			Code:            dc.Code,
			Description:     dc.Description,
			ApplicationID:   dc.ApplicationID,
			ApplicationName: dc.Application.Name,
			Enabled:         dc.Status == "active",
			CreatedAt:       dc.CreatedAt.Format("2006-01-02 15:04:05"),
			UpdatedAt:       dc.UpdatedAt.Format("2006-01-02 15:04:05"),
			Creator:         creator,
		})
	}

	response.Success(c, result)
}

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

	var dynamicCode model.DynamicCode
	if err := database.DB.Preload("Application").Preload("Creator").Where("id = ?", id).First(&dynamicCode).Error; err != nil {
		response.Error(c, 404, "动态代码不存在")
		return
	}

	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", dynamicCode.ApplicationID, userID).First(&app).Error; err != nil {
		response.Error(c, 403, "无权限访问此动态代码")
		return
	}

	type DynamicCodeResponse struct {
		ID              uint   `json:"id"`
		Name            string `json:"name"`
		Code            string `json:"code"`
		Description     string `json:"description"`
		ApplicationID   uint   `json:"application_id"`
		ApplicationName string `json:"application_name"`
		Enabled         bool   `json:"enabled"`
		CreatedAt       string `json:"created_at"`
		UpdatedAt       string `json:"updated_at"`
		Creator         *struct {
			ID       uint   `json:"id"`
			Username string `json:"username"`
		} `json:"creator,omitempty"`
	}

	var creator *struct {
		ID       uint   `json:"id"`
		Username string `json:"username"`
	}
	if dynamicCode.UserID != nil && dynamicCode.Creator.ID != 0 {
		creator = &struct {
			ID       uint   `json:"id"`
			Username string `json:"username"`
		}{
			ID:       dynamicCode.Creator.ID,
			Username: dynamicCode.Creator.Username,
		}
	}

	result := DynamicCodeResponse{
		ID:              dynamicCode.ID,
		Name:            dynamicCode.Name,
		Code:            dynamicCode.Code,
		Description:     dynamicCode.Description,
		ApplicationID:   dynamicCode.ApplicationID,
		ApplicationName: dynamicCode.Application.Name,
		Enabled:         dynamicCode.Status == "active",
		CreatedAt:       dynamicCode.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:       dynamicCode.UpdatedAt.Format("2006-01-02 15:04:05"),
		Creator:         creator,
	}

	response.Success(c, result)
}

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

	var req struct {
		Name          string `json:"name" binding:"required"`
		Code          string `json:"code" binding:"required"`
		Description   string `json:"description"`
		Enabled       bool   `json:"enabled"`
		ApplicationID uint   `json:"application_id" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误: "+err.Error())
		return
	}

	if err := validateDynamicCode(req.Code); err != nil {
		response.Error(c, 400, "代码语法错误: "+err.Error())
		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
	}

	status := "inactive"
	if req.Enabled {
		status = "active"
	}

	key := normalizeKey(req.Name)

	var existingCode model.DynamicCode
	err := database.DB.Unscoped().Where("key = ?", key).First(&existingCode).Error
	if err == nil {
		if existingCode.DeletedAt.Valid {
			database.DB.Unscoped().Delete(&existingCode)
		} else {
			response.Error(c, 400, "该名称的动态代码已存在")
			return
		}
	}

	dynamicCode := model.DynamicCode{
		UserID:        &userID,
		ApplicationID: req.ApplicationID,
		Name:          req.Name,
		Key:           key,
		Code:          req.Code,
		Description:   req.Description,
		Status:        status,
	}

	if err := database.DB.Create(&dynamicCode).Error; err != nil {
		if strings.Contains(err.Error(), "UNIQUE constraint failed") || strings.Contains(err.Error(), "constraint failed") {
			response.Error(c, 400, "该名称的动态代码已存在")
			return
		}
		response.Error(c, 500, "创建失败: "+err.Error())
		return
	}

	response.Success(c, dynamicCode)
}

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

	id := c.Param("id")

	var dynamicCode model.DynamicCode
	if err := database.DB.Where("id = ?", id).First(&dynamicCode).Error; err != nil {
		response.Error(c, 404, "动态代码不存在")
		return
	}

	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", dynamicCode.ApplicationID, userID).First(&app).Error; err != nil {
		response.Error(c, 403, "无权限操作此动态代码")
		return
	}

	var req struct {
		Name          string `json:"name" binding:"required"`
		Code          string `json:"code" binding:"required"`
		Description   string `json:"description"`
		Enabled       bool   `json:"enabled"`
		ApplicationID uint   `json:"application_id" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	if err := validateDynamicCode(req.Code); err != nil {
		response.Error(c, 400, "代码语法错误: "+err.Error())
		return
	}

	if req.ApplicationID != dynamicCode.ApplicationID {
		var newApp model.Application
		if err := database.DB.Where("id = ? AND user_id = ?", req.ApplicationID, userID).First(&newApp).Error; err != nil {
			response.Error(c, 403, "无权限操作此应用")
			return
		}
		dynamicCode.ApplicationID = req.ApplicationID
	}

	status := "inactive"
	if req.Enabled {
		status = "active"
	}

	dynamicCode.Name = req.Name
	dynamicCode.Key = normalizeKey(req.Name)
	dynamicCode.Code = req.Code
	dynamicCode.Description = req.Description
	dynamicCode.Status = status

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

	response.Success(c, dynamicCode)
}

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

	id := c.Param("id")

	var dynamicCode model.DynamicCode
	if err := database.DB.Where("id = ?", id).First(&dynamicCode).Error; err != nil {
		response.Error(c, 404, "动态代码不存在")
		return
	}

	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", dynamicCode.ApplicationID, userID).First(&app).Error; err != nil {
		response.Error(c, 403, "无权限操作此动态代码")
		return
	}

	if err := database.DB.Delete(&dynamicCode).Error; err != nil {
		response.Error(c, 500, "删除失败")
		return
	}

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

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

	id := c.Param("id")

	var dynamicCode model.DynamicCode
	if err := database.DB.Where("id = ?", id).First(&dynamicCode).Error; err != nil {
		response.Error(c, 404, "动态代码不存在")
		return
	}

	var app model.Application
	if err := database.DB.Where("id = ? AND user_id = ?", dynamicCode.ApplicationID, userID).First(&app).Error; err != nil {
		response.Error(c, 403, "无权限操作此动态代码")
		return
	}

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

	status := "inactive"
	if req.Enabled {
		status = "active"
	}

	dynamicCode.Status = status

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

	response.Success(c, dynamicCode)
}

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

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

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

	response.Success(c, gin.H{"message": "批量删除成功"})
}

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

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	status := "inactive"
	if req.Enabled {
		status = "active"
	}

	if err := database.DB.Model(&model.DynamicCode{}).Where("id IN ? AND application_id IN ?", req.IDs, applicationIDs).Update("status", status).Error; err != nil {
		response.Error(c, 500, "批量更新状态失败")
		return
	}

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

type RiskControlRule struct {
	ID        uint    `json:"id"`
	Type      string  `json:"type"`
	Value     string  `json:"value"`
	Reason    string  `json:"reason"`
	Status    string  `json:"status"`
	ExpiresAt *string `json:"expires_at"`
	CreatedAt string  `json:"created_at"`
}

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	var rules []model.RiskControlRule
	if err := database.DB.Where("user_id = ? OR application_id IN ?", userID, applicationIDs).Order("created_at DESC").Find(&rules).Error; err != nil {
		response.Error(c, 500, "获取风控规则失败")
		return
	}

	var result []gin.H
	for _, rule := range rules {
		var expiresAt *string
		if rule.ExpiresAt != nil {
			t := rule.ExpiresAt.Format("2006-01-02 15:04:05")
			expiresAt = &t
		}

		var appID *uint
		if rule.ApplicationID != nil {
			appID = rule.ApplicationID
		}

		result = append(result, gin.H{
			"id":             rule.ID,
			"type":           rule.Type,
			"value":          rule.Value,
			"reason":         rule.Reason,
			"status":         rule.Status,
			"expires_at":     expiresAt,
			"application_id": appID,
			"is_global":      rule.ApplicationID == nil,
			"created_at":     rule.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	response.Success(c, result)
}

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

	var req struct {
		Type          string  `json:"type" binding:"required"`
		Value         string  `json:"value" binding:"required"`
		Reason        string  `json:"reason"`
		ExpiresAt     *string `json:"expires_at"`
		ApplicationID *uint   `json:"application_id"`
		IsGlobal      bool    `json:"is_global"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		log.Printf("[ERROR] Failed to bind JSON: %v", err)
		response.Error(c, 400, "参数错误")
		return
	}

	log.Printf("[DEBUG] Create risk control rule: type=%s, value=%s, is_global=%v, application_id=%v", req.Type, req.Value, req.IsGlobal, req.ApplicationID)

	var appID *uint
	switch req.Type {
	case "user":
		if req.ApplicationID == nil {
			response.Error(c, 400, "用户封禁规则必须指定应用")
			return
		}
		var application model.Application
		if err := database.DB.Where("id = ? AND user_id = ?", *req.ApplicationID, userID).First(&application).Error; err != nil {
			response.Error(c, 404, "应用不存在或无权限")
			return
		}
		appID = req.ApplicationID
	case "ip", "device", "region":
		if !req.IsGlobal && req.ApplicationID != nil {
			var application model.Application
			if err := database.DB.Where("id = ? AND user_id = ?", *req.ApplicationID, userID).First(&application).Error; err != nil {
				response.Error(c, 404, "应用不存在或无权限")
				return
			}
			appID = req.ApplicationID
		} else {
			appID = nil
		}
	default:
		response.Error(c, 400, "不支持的规则类型")
		return
	}

	rule := model.RiskControlRule{
		UserID:        userID,
		ApplicationID: appID,
		Type:          req.Type,
		Value:         req.Value,
		Reason:        req.Reason,
		Status:        "active",
	}

	if req.ExpiresAt != nil && *req.ExpiresAt != "" {
		t, err := time.Parse("2006-01-02T15:04", *req.ExpiresAt)
		if err == nil {
			rule.ExpiresAt = &t
		} else {
			log.Printf("[WARN] Failed to parse expires_at: %v", err)
		}
	}

	log.Printf("[DEBUG] Creating rule: %+v", rule)

	if err := database.DB.Create(&rule).Error; err != nil {
		log.Printf("[ERROR] Failed to create risk control rule: %v", err)
		response.Error(c, 500, "创建风控规则失败")
		return
	}

	var expiresAt *string
	if rule.ExpiresAt != nil {
		t := rule.ExpiresAt.Format("2006-01-02 15:04:05")
		expiresAt = &t
	}

	var appIDResp *uint
	if rule.ApplicationID != nil {
		appIDResp = rule.ApplicationID
	}

	response.Success(c, gin.H{
		"id":             rule.ID,
		"type":           rule.Type,
		"value":          rule.Value,
		"reason":         rule.Reason,
		"status":         rule.Status,
		"expires_at":     expiresAt,
		"application_id": appIDResp,
		"is_global":      rule.ApplicationID == nil,
		"created_at":     rule.CreatedAt.Format("2006-01-02 15:04:05"),
	})
}

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

	var req struct {
		Type      string  `json:"type" binding:"required"`
		Value     string  `json:"value" binding:"required"`
		Reason    string  `json:"reason"`
		ExpiresAt *string `json:"expires_at"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	var rule model.RiskControlRule
	if err := database.DB.Where("id = ? AND application_id IN ?", ruleID, applicationIDs).First(&rule).Error; err != nil {
		response.Error(c, 404, "风控规则不存在")
		return
	}

	rule.Type = req.Type
	rule.Value = req.Value
	rule.Reason = req.Reason

	if req.ExpiresAt != nil && *req.ExpiresAt != "" {
		t, err := time.Parse("2006-01-02T15:04", *req.ExpiresAt)
		if err == nil {
			rule.ExpiresAt = &t
		}
	} else {
		rule.ExpiresAt = nil
	}

	if err := database.DB.Save(&rule).Error; err != nil {
		response.Error(c, 500, "更新风控规则失败")
		return
	}

	var expiresAt *string
	if rule.ExpiresAt != nil {
		t := rule.ExpiresAt.Format("2006-01-02 15:04:05")
		expiresAt = &t
	}

	response.Success(c, RiskControlRule{
		ID:        rule.ID,
		Type:      rule.Type,
		Value:     rule.Value,
		Reason:    rule.Reason,
		Status:    rule.Status,
		ExpiresAt: expiresAt,
		CreatedAt: rule.CreatedAt.Format("2006-01-02 15:04:05"),
	})
}

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	if err := database.DB.Where("id = ? AND application_id IN ?", ruleID, applicationIDs).Delete(&model.RiskControlRule{}).Error; err != nil {
		response.Error(c, 500, "删除风控规则失败")
		return
	}

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

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

	var req struct {
		Status string `json:"status" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	var rule model.RiskControlRule
	if err := database.DB.Where("id = ? AND application_id IN ?", ruleID, applicationIDs).First(&rule).Error; err != nil {
		response.Error(c, 404, "风控规则不存在")
		return
	}

	rule.Status = req.Status
	if err := database.DB.Save(&rule).Error; err != nil {
		response.Error(c, 500, "更新状态失败")
		return
	}

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

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

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

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

	response.Success(c, gin.H{"message": "批量删除成功"})
}

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

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

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

	var applicationIDs []uint
	for _, app := range applications {
		applicationIDs = append(applicationIDs, app.ID)
	}

	if err := database.DB.Model(&model.RiskControlRule{}).Where("id IN ? AND application_id IN ?", req.IDs, applicationIDs).Update("status", req.Status).Error; err != nil {
		response.Error(c, 500, "批量更新状态失败")
		return
	}

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