package app

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"verification-platform-backend/internal/database"
	"verification-platform-backend/internal/model"
	"verification-platform-backend/internal/service"
	"verification-platform-backend/internal/utils/httputil"
	"verification-platform-backend/internal/utils/smtputil"
	"verification-platform-backend/pkg/jwt"
	"verification-platform-backend/pkg/response"

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

func SetupDynamicRoutes(r *gin.RouterGroup) {
	dynamicCode := r.Group("/dynamic-code")
	{
		dynamicCode.POST("/:key/execute", handleExecuteDynamicCode)
	}
}

func handleExecuteDynamicCode(c *gin.Context) {
	var token string
	authHeader := c.GetHeader("Authorization")
	if authHeader != "" {
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) == 2 && parts[0] == "Bearer" {
			token = parts[1]
		}
	}

	if token == "" {
		token = c.Query("token")
	}

	if token == "" {
		response.Error(c, http.StatusUnauthorized, "Authorization header is required")
		return
	}

	claims, err := jwt.ParseToken(token)
	if err != nil {
		response.Error(c, http.StatusUnauthorized, "Invalid token")
		return
	}

	if time.Now().Unix() > claims.ExpiresAt.Unix() {
		response.Error(c, http.StatusUnauthorized, "Token expired")
		return
	}

	c.Set("user_id", claims.UserID)
	c.Set("username", claims.Username)
	c.Set("role", claims.Role)

	appKey := c.Param("appKey")
	key := c.Param("key")

	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 appUser model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", claims.UserID, app.ID).First(&appUser).Error; err != nil {
		response.Error(c, http.StatusForbidden, "无权访问该应用的动态代码")
		return
	}

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

	if dynamicCode.Status != "active" {
		response.Error(c, 400, "动态代码未启用")
		return
	}

	var req struct {
		Params map[string]interface{} `json:"params"`
		UserID *uint                  `json:"user_id,omitempty"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	startTime := time.Now()

	vm := goja.New()

	appData := map[string]interface{}{
		"id":                    app.ID,
		"name":                  app.Name,
		"description":           app.Description,
		"app_key":               app.AppKey,
		"status":                app.Status,
		"billing_type":          app.BillingType,
		"deduction_mode":        app.DeductionMode,
		"deduction_type":        app.DeductionType,
		"deduction_interval":    app.DeductionInterval,
		"deduction_unit":        app.DeductionUnit,
		"deduction_amount":      app.DeductionAmount,
		"enable_trial":          app.EnableTrial,
		"trial_balance":         app.TrialBalance,
		"trial_days":            app.TrialDays,
		"enable_free_period":    app.EnableFreePeriod,
		"free_period_type":      app.FreePeriodType,
		"free_period_start":     app.FreePeriodStart,
		"free_period_end":       app.FreePeriodEnd,
		"free_period_weekdays":  app.FreePeriodWeekdays,
		"free_period_start_time": app.FreePeriodStartTime,
		"free_period_end_time":  app.FreePeriodEndTime,
		"max_devices":           app.MaxDevices,
		"bind_type":             app.BindType,
		"multi_open_mode":       app.MultiOpenMode,
		"max_instances":         app.MaxInstances,
		"login_policy":          app.LoginPolicy,
		"max_attempts":          app.MaxAttempts,
		"lock_duration":         app.LockDuration,
		"heartbeat_interval":    app.HeartbeatInterval,
		"heartbeat_timeout":     app.HeartbeatTimeout,
		"change_limit":          app.ChangeLimit,
		"change_interval":       app.ChangeInterval,
		"change_exceed_action":  app.ChangeExceedAction,
		"change_deduct_amount":  app.ChangeDeductAmount,
	}
	if err := vm.Set("app", appData); err != nil {
		response.Error(c, 500, "应用数据设置失败")
		return
	}

	var constants []model.CloudConstant
	database.DB.Where("app_id = ? AND status = ?", app.ID, "active").Find(&constants)
	constantsData := make(map[string]interface{})
	for _, c := range constants {
		constantsData[c.Key] = c.Value
	}
	if err := vm.Set("constants", constantsData); err != nil {
		response.Error(c, 500, "云端常量设置失败")
		return
	}

	var cloudVariables []model.CloudVariable
	database.DB.Where("app_id = ? AND status = ?", app.ID, "active").Find(&cloudVariables)
	appVariables := make(map[string]interface{})
	for _, v := range cloudVariables {
		appVariables[v.Key] = v.DefaultValue
	}
	if err := vm.Set("appVariables", appVariables); err != nil {
		response.Error(c, 500, "云端变量设置失败")
		return
	}

	userData := map[string]interface{}{}
	subscription := map[string]interface{}{}
	userVariables := map[string]interface{}{}
	devices := []map[string]interface{}{}

	if req.UserID != nil {
		var user model.AppUser
		if err := database.DB.Where("id = ? AND application_id = ?", *req.UserID, app.ID).First(&user).Error; err == nil {
			userData = map[string]interface{}{
				"id":            user.ID,
				"username":      user.Username,
				"email":         user.Email,
				"status":        user.Status,
				"device_id":     user.DeviceID,
				"avatar":        user.Avatar,
				"created_at":    user.CreatedAt,
				"last_login_at": user.LastLoginAt,
			}

			subscription = map[string]interface{}{
				"balance":       user.Balance,
				"is_trial_user": user.IsTrialUser,
				"trial_start_at": user.TrialStartAt,
				"trial_end_at":  user.TrialEndAt,
				"expiry_at":     user.ExpiryAt,
				"is_expired":    user.ExpiryAt != nil && user.ExpiryAt.Before(time.Now()),
				"is_lifetime":   user.Balance == -1,
				"days_remaining": calculateDaysRemaining(user.ExpiryAt, user.Balance),
			}

			var userDevices []model.UserDevice
			database.DB.Where("user_id = ? AND application_id = ?", user.ID, app.ID).Find(&userDevices)
			for _, d := range userDevices {
				devices = append(devices, map[string]interface{}{
					"id":           d.ID,
					"device_id":    d.DeviceID,
					"device_name":  d.DeviceName,
					"device_type":  d.DeviceType,
					"status":       d.Status,
					"created_at":   d.CreatedAt,
				})
			}

			var userVars []model.UserVariable
			database.DB.Where("user_id = ? AND app_id = ?", user.ID, app.ID).Find(&userVars)
			for _, v := range userVars {
				userVariables[v.VarName] = v.VarValue
			}
		}
	}

	if err := vm.Set("user", userData); err != nil {
		response.Error(c, 500, "用户数据设置失败")
		return
	}
	if err := vm.Set("subscription", subscription); err != nil {
		response.Error(c, 500, "订阅数据设置失败")
		return
	}
	if err := vm.Set("userVariables", userVariables); err != nil {
		response.Error(c, 500, "用户变量设置失败")
		return
	}
	if err := vm.Set("devices", devices); err != nil {
		response.Error(c, 500, "设备数据设置失败")
		return
	}

	for k, v := range req.Params {
		if err := vm.Set(k, v); err != nil {
			response.Error(c, 500, "参数设置失败")
			return
		}
	}

	if err := vm.Set("params", req.Params); err != nil {
		response.Error(c, 500, "参数设置失败")
		return
	}

	httpClient := httputil.NewHTTPClient(10 * time.Second)
	httpObj := map[string]interface{}{
		"get": func(url string, headers map[string]interface{}) map[string]interface{} {
			convertedHeaders := make(map[string]string)
			for k, v := range headers {
				convertedHeaders[k] = fmt.Sprintf("%v", v)
			}
			resp := httpClient.Get(url, convertedHeaders)
			return map[string]interface{}{
				"statusCode": resp.StatusCode,
				"status":     resp.Status,
				"headers":    resp.Headers,
				"body":       resp.Body,
				"json":       resp.JSON,
				"error":      resp.Error,
			}
		},
		"post": func(url string, headers map[string]interface{}, body interface{}) map[string]interface{} {
			convertedHeaders := make(map[string]string)
			for k, v := range headers {
				convertedHeaders[k] = fmt.Sprintf("%v", v)
			}
			resp := httpClient.Post(url, convertedHeaders, body)
			return map[string]interface{}{
				"statusCode": resp.StatusCode,
				"status":     resp.Status,
				"headers":    resp.Headers,
				"body":       resp.Body,
				"json":       resp.JSON,
				"error":      resp.Error,
			}
		},
	}
	if err := vm.Set("http", httpObj); err != nil {
		response.Error(c, 500, "HTTP对象设置失败")
		return
	}

	dbObj := map[string]interface{}{
		"getRecords": func(variableKey string, page, pageSize int) map[string]interface{} {
			return getRecords(app.ID, req.UserID, variableKey, page, pageSize)
		},
		"deleteRecord": func(variableKey string, recordID uint) map[string]interface{} {
			return deleteRecord(app.ID, req.UserID, variableKey, recordID)
		},
		"deleteRecords": func(variableKey string, recordIDs []uint) map[string]interface{} {
			return deleteRecords(app.ID, req.UserID, variableKey, recordIDs)
		},
	}
	if err := vm.Set("db", dbObj); err != nil {
		response.Error(c, 500, "数据库对象设置失败")
		return
	}

	smtpObj := map[string]interface{}{
		"send": func(config map[string]interface{}, to []string, subject, body string, html bool) *smtputil.SMTPResult {
			smtpConfig := smtputil.SMTPConfig{
				Host:     getString(config, "host"),
				Port:     getInt(config, "port", 587),
				Username: getString(config, "username"),
				Password: getString(config, "password"),
				From:     getString(config, "from"),
				UseTLS:   getBool(config, "use_tls", true),
			}
			client := smtputil.NewSMTPClient(smtpConfig, 30*time.Second)
			return client.Send(smtputil.EmailMessage{
				To:      to,
				Subject: subject,
				Body:    body,
				HTML:    html,
			})
		},
	}
	if err := vm.Set("smtp", smtpObj); err != nil {
		response.Error(c, 500, "SMTP对象设置失败")
		return
	}

	value, err := vm.RunString("(function() { " + dynamicCode.Code + " })()")
	if err != nil {
		response.Error(c, 400, "代码执行错误: "+err.Error())
		return
	}

	executionTime := time.Since(startTime).Milliseconds()

	result := value.Export()

	if actionMap, ok := result.(map[string]interface{}); ok {
		if action, hasAction := actionMap["action"]; hasAction {
			switch action {
			case "extend_time":
				if err := handleExtendTime(app.ID, actionMap); err != nil {
					response.Error(c, 500, "执行加时操作失败: "+err.Error())
					return
				}
			case "deduct_points":
				if err := handleDeductPoints(app.ID, actionMap); err != nil {
					response.Error(c, 500, "执行扣点操作失败: "+err.Error())
					return
				}
			case "update_user_variable":
				appID := app.ID
				if err := handleUpdateUserVariable(&appID, req.UserID, actionMap); err != nil {
					response.Error(c, 500, "更新用户变量失败: "+err.Error())
					return
				}
			case "update_app_variable":
				if err := handleUpdateAppVariable(app.ID, actionMap); err != nil {
					response.Error(c, 500, "更新应用变量失败: "+err.Error())
					return
				}
			case "add_record":
				if err := handleAddRecord(app.ID, req.UserID, actionMap); err != nil {
					response.Error(c, 500, "添加记录失败: "+err.Error())
					return
				}
			}
		}
	}

	response.Success(c, gin.H{
		"result":         result,
		"execution_time": executionTime,
	})
}

func calculateDaysRemaining(expiryAt *time.Time, balance float64) int {
	if balance == -1 {
		return -1
	}
	if expiryAt == nil {
		return 0
	}
	remaining := int(time.Until(*expiryAt).Hours() / 24)
	if remaining < 0 {
		return 0
	}
	return remaining
}

func handleExtendTime(appID uint, actionMap map[string]interface{}) error {
	userID, ok := actionMap["user_id"].(float64)
	if !ok {
		return nil
	}

	days, ok := actionMap["days"].(float64)
	if !ok {
		return nil
	}

	var user model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", uint(userID), appID).First(&user).Error; err != nil {
		return err
	}

	if user.Balance == -1 {
		return nil
	}

	user.Balance += float64(days)

	return database.DB.Save(&user).Error
}

func handleDeductPoints(appID uint, actionMap map[string]interface{}) error {
	userID, ok := actionMap["user_id"].(float64)
	if !ok {
		return nil
	}

	points, ok := actionMap["points"].(float64)
	if !ok {
		return nil
	}

	var user model.AppUser
	if err := database.DB.Where("id = ? AND application_id = ?", uint(userID), appID).First(&user).Error; err != nil {
		return err
	}

	if user.Balance == -1 {
		return nil
	}

	user.Balance -= points
	if user.Balance < 0 {
		user.Balance = 0
	}

	return database.DB.Save(&user).Error
}

func handleUpdateUserVariable(appID *uint, userID *uint, actionMap map[string]interface{}) error {
	if userID == nil {
		return nil
	}

	varName, ok := actionMap["name"].(string)
	if !ok {
		return nil
	}

	varValue, ok := actionMap["value"].(string)
	if !ok {
		if v, ok := actionMap["value"]; ok {
			varValue = toString(v)
		} else {
			return nil
		}
	}

	var userVar model.UserVariable
	if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", *userID, appID, varName).First(&userVar).Error; err != nil {
		userVar = model.UserVariable{
			UserID:   *userID,
			AppID:    *appID,
			VarName:  varName,
			VarValue: varValue,
		}
		return database.DB.Create(&userVar).Error
	}

	userVar.VarValue = varValue
	return database.DB.Save(&userVar).Error
}

func handleUpdateAppVariable(appID uint, actionMap map[string]interface{}) error {
	varName, ok := actionMap["name"].(string)
	if !ok {
		return nil
	}

	varValue, ok := actionMap["value"].(string)
	if !ok {
		if v, ok := actionMap["value"]; ok {
			varValue = toString(v)
		} else {
			return nil
		}
	}

	var appVar model.CloudVariable
	if err := database.DB.Where("app_id = ? AND key = ?", appID, varName).First(&appVar).Error; err != nil {
		return err
	}

	appVar.DefaultValue = varValue
	return database.DB.Save(&appVar).Error
}

func toString(v interface{}) string {
	switch val := v.(type) {
	case string:
		return val
	case float64:
		return string(rune(int(val)))
	case int:
		return string(rune(val))
	default:
		return ""
	}
}

func handleAddRecord(appID uint, userID *uint, actionMap map[string]interface{}) error {
	variableKey, ok := actionMap["variable_key"].(string)
	if !ok {
		return fmt.Errorf("缺少variable_key参数")
	}

	recordData, ok := actionMap["record_data"]
	if !ok {
		return fmt.Errorf("缺少record_data参数")
	}

	var variable model.CloudVariable
	if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
		return fmt.Errorf("云端变量不存在: %s", variableKey)
	}

	if variable.VarType != "stream" {
		return fmt.Errorf("该变量不是记录类型")
	}

	dataBytes, err := json.Marshal(recordData)
	if err != nil {
		return fmt.Errorf("序列化记录数据失败: %v", err)
	}

	record := model.CloudVariableRecord{
		CloudVariableID: variable.ID,
		Data:            string(dataBytes),
	}

	if variable.Scope == "user" && userID != nil {
		appUserID := *userID
		record.AppUserID = &appUserID
	}

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

	if variable.MaxRecords > 0 {
		var total int64
		database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID).Count(&total)
		if int(total) > variable.MaxRecords {
			deleteCount := int(total) - variable.MaxRecords
			var oldRecords []model.CloudVariableRecord
			database.DB.Where("cloud_variable_id = ?", variable.ID).
				Order("created_at ASC").
				Limit(deleteCount).
				Find(&oldRecords)
			for _, oldRecord := range oldRecords {
				database.DB.Delete(&oldRecord)
			}
		}
	}

	return nil
}

func getRecords(appID uint, userID *uint, variableKey string, page, pageSize int) map[string]interface{} {
	result := map[string]interface{}{
		"success": false,
		"records": []interface{}{},
		"total":   0,
		"page":    page,
		"pageSize": pageSize,
	}

	var variable model.CloudVariable
	if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
		result["error"] = "云端变量不存在"
		return result
	}

	if variable.VarType != "stream" {
		result["error"] = "该变量不是记录类型"
		return result
	}

	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 20
	}

	var total int64
	query := database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID)
	if variable.Scope == "user" && userID != nil {
		query = query.Where("app_user_id = ?", *userID)
	}
	query.Count(&total)

	var records []model.CloudVariableRecord
	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&records).Error; err != nil {
		result["error"] = "查询记录失败"
		return result
	}

	var recordList []interface{}
	for _, record := range records {
		var data interface{}
		if err := json.Unmarshal([]byte(record.Data), &data); err == nil {
			recordList = append(recordList, map[string]interface{}{
				"id":         record.ID,
				"data":       data,
				"created_at": record.CreatedAt,
			})
		}
	}

	result["success"] = true
	result["records"] = recordList
	result["total"] = total
	return result
}

func deleteRecord(appID uint, userID *uint, variableKey string, recordID uint) map[string]interface{} {
	result := map[string]interface{}{
		"success": false,
	}

	var variable model.CloudVariable
	if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
		result["error"] = "云端变量不存在"
		return result
	}

	if variable.VarType != "stream" {
		result["error"] = "该变量不是记录类型"
		return result
	}

	query := database.DB.Where("id = ? AND cloud_variable_id = ?", recordID, variable.ID)
	if variable.Scope == "user" && userID != nil {
		query = query.Where("app_user_id = ?", *userID)
	}

	if err := query.Delete(&model.CloudVariableRecord{}).Error; err != nil {
		result["error"] = "删除记录失败"
		return result
	}

	result["success"] = true
	return result
}

func deleteRecords(appID uint, userID *uint, variableKey string, recordIDs []uint) map[string]interface{} {
	result := map[string]interface{}{
		"success": false,
		"deleted": 0,
	}

	var variable model.CloudVariable
	if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
		result["error"] = "云端变量不存在"
		return result
	}

	if variable.VarType != "stream" {
		result["error"] = "该变量不是记录类型"
		return result
	}

	query := database.DB.Where("id IN ? AND cloud_variable_id = ?", recordIDs, variable.ID)
	if variable.Scope == "user" && userID != nil {
		query = query.Where("app_user_id = ?", *userID)
	}

	deleteResult := query.Delete(&model.CloudVariableRecord{})
	if deleteResult.Error != nil {
		result["error"] = "删除记录失败"
		return result
	}

	result["success"] = true
	result["deleted"] = deleteResult.RowsAffected
	return result
}

func getString(m map[string]interface{}, key string) string {
	if v, ok := m[key]; ok {
		if s, ok := v.(string); ok {
			return s
		}
	}
	return ""
}

func getInt(m map[string]interface{}, key string, defaultValue int) int {
	if v, ok := m[key]; ok {
		switch val := v.(type) {
		case int:
			return val
		case float64:
			return int(val)
		}
	}
	return defaultValue
}

func getBool(m map[string]interface{}, key string, defaultValue bool) bool {
	if v, ok := m[key]; ok {
		if b, ok := v.(bool); ok {
			return b
		}
	}
	return defaultValue
}
