package models

import (
	"crypto/aes"
	"crypto/cipher"
	craned "crypto/rand"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	orm "go-admin/common/global"
	"go-admin/logger"
	"io"
	"math/rand"
	"time"
)

// gen:qs
//
//go:generate goqueryset -in config.go
type Config struct {
	Model

	Name  string `gorm:"unique_index;not null"`
	Value string `gorm:"size:65535;not null"`
}

func (m *Config) TableName() string {
	return "config"
}

type PayConfig struct {
	MemberFee         uint32 `json:"member_fee"`
	DepositFee        uint32 `json:"deposit_fee"`
	NotifyUrl         string `json:"notify_url"`
	RefundNotifyUrl   string `json:"refund_notify_url"`
	DwRefundNotifyUrl string `json:"dw_refund_notify_url"`
}

const (
	ConfigNamePay            = "pay_config"              // 支付配置
	ConfigNameMember         = "member_config"           // 会员配置
	ConfigNameMemberVm       = "member_vm_config"        // 会员积分配置
	ConfigNameAttendanceVm   = "attendance_vm_config"    // 签到积分配置
	ConfigActivityRenewal    = "activity_renewal_config" // 活动配置
	ConfigRecycleCard        = "recycle_card_config"     // 回收卡配置
	ConfigCooperativePayInfo = "cooperative_pay_info"    // 合作商支付设置
	ConfigErpOrderShowInfo   = "erp_order_show_config"   // 零售订单显示设置
	ConfigSystemSmsCount     = "sms_config"              // 获取系统每月短信限额
	ConfigTestUserInfo       = "test_user_Info"          // 获取测试用户uid
	ConfigNameLotteryLimit   = "lottery_config"          // 积分抽奖配置
)

func PayConfigInfo() (*PayConfig, error) {
	payConfig := new(PayConfig)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigNamePay).Find(&configAllocation).Error
	//err := NewConfigQuerySet(DB).NameEq(ConfigNamePay).One(&configAllocation)
	if err != nil {
		logger.Errorf("err:", err)
		return payConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), payConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return payConfig, err
	}

	return payConfig, nil
}

type MemberConfig struct {
	MemberLever   uint32 `json:"member_lever"`   // 会员等级
	MemberFee     uint32 `json:"member_fee"`     // 会员费
	MemberDeposit uint32 `json:"member_deposit"` // 押金
	CardMax       uint32 `json:"card_max"`
}

func MemberConfigInfo() ([]MemberConfig, error) {
	var memberConfigs []MemberConfig
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigNameMember).Find(&configAllocation).Error
	//err := NewConfigQuerySet(DB).NameEq(ConfigNameMember).One(&configAllocation)
	if err != nil {
		logger.Errorf("err:", err)
		return memberConfigs, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), &memberConfigs)
	if err != nil {
		logger.Errorf("err:", err)
		return memberConfigs, err
	}

	return memberConfigs, nil
}

func GetMemberConfig(level uint32) (*MemberConfig, error) {
	if level == 3 {
		level = 2
	}
	info, err := MemberConfigInfo()
	if err != nil {
		return nil, err
	}
	for _, config := range info {
		if config.MemberLever == level {
			return &config, nil
		}
	}

	return nil, errors.New("level err")
}

type MemberVmConfig struct {
	MemberLever        uint32 `json:"member_lever"` // 会员等级
	MemberVm           uint32 `json:"member_vm"`
	Invite1Vm          uint32 `json:"invite_1_vm"`
	Invite2Vm          uint32 `json:"invite_2_vm"`
	AutomationMemberVm uint32 `json:"automation_member_vm"`
}

func memberVmConfigInfo() ([]MemberVmConfig, error) {
	var memberVmConfigs []MemberVmConfig
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigNameMemberVm).Find(&configAllocation).Error
	//err := NewConfigQuerySet(DB).NameEq(ConfigNameMemberVm).One(&configAllocation)
	if err != nil {
		logger.Errorf("err:", err)
		return memberVmConfigs, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), &memberVmConfigs)
	if err != nil {
		logger.Errorf("err:", err)
		return memberVmConfigs, err
	}

	return memberVmConfigs, nil
}

func GetMemberVmConfig(level uint32) (*MemberVmConfig, error) {
	if level == 3 {
		return nil, errors.New("level is 3")
	}
	info, err := memberVmConfigInfo()
	if err != nil {
		return nil, err
	}
	for _, config := range info {
		if config.MemberLever == level {
			return &config, nil
		}
	}

	return nil, errors.New("level err")
}

type AttendanceVmConfig struct {
	VmDay1 uint32 `json:"vm_day_1"`
	VmDay2 uint32 `json:"vm_day_2"`
	VmDay3 uint32 `json:"vm_day_3"`
	VmDay4 uint32 `json:"vm_day_4"`
	VmDay5 uint32 `json:"vm_day_5"`
	VmDay6 uint32 `json:"vm_day_6"`
	VmDay7 uint32 `json:"vm_day_7"`
}

func AttendanceVmConfigInfo() (*AttendanceVmConfig, error) {
	attendanceConfig := new(AttendanceVmConfig)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigNameAttendanceVm).Find(&configAllocation).Error
	//err := NewConfigQuerySet(DB).NameEq(ConfigNameAttendanceVm).One(&configAllocation)
	if err != nil {
		logger.Errorf("err:", err)
		return attendanceConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), attendanceConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return attendanceConfig, err
	}

	return attendanceConfig, nil
}

func (m *AttendanceVmConfig) Vm(days uint32) uint32 {
	vm := uint32(0)
	switch days % 7 {
	case 1:
		vm = m.VmDay1
	case 2:
		vm = m.VmDay2
	case 3:
		vm = m.VmDay3
	case 4:
		vm = m.VmDay4
	case 5:
		vm = m.VmDay5
	case 6:
		vm = m.VmDay6
	case 0:
		vm = m.VmDay7
	}

	return vm
}

type ActivityRenewalConfig struct {
	CouponValidity     int `json:"coupon_validity"`
	ActivityContinuity int `json:"activity_continuity"`
	PopTrap            int `json:"pop_trap"`
	// activity_renewal_config
}

func ActivityRenewalConfigInfo() (ActivityRenewalConfig, error) {
	activityRenewalConfig := ActivityRenewalConfig{}
	var configAllocation Config
	err := orm.Eloquent.Table("config").
		Where("name=?", ConfigActivityRenewal).Find(&configAllocation).Error
	//err := NewConfigQuerySet(DB).NameEq(ConfigActivityRenewal).One(&configAllocation)
	if err != nil {
		logger.Errorf("err:", err)
		return activityRenewalConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), &activityRenewalConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return activityRenewalConfig, err
	}

	return activityRenewalConfig, nil
}

func ActivityRenewalConfigUpdate(activity ActivityRenewalConfig) (ActivityRenewalConfig, error) {
	bytes, err := json.Marshal(activity)
	if err != nil {
		logger.Errorf("err:", err)
		return activity, err
	}

	orm.Eloquent.Table("config").
		Where("name=?", ConfigActivityRenewal).Update("Value", string(bytes))
	if err != nil {
		logger.Errorf("err:", err)
		return activity, err
	}

	return activity, nil
}

func GetActivityRenewalConfig() ActivityRenewalConfig {
	info, err := ActivityRenewalConfigInfo()
	if err != nil {
		logger.Errorf("info err:", err)
		return info
	}
	return info
}

type RecycleCardConfig struct {
	RebateRate uint32 `json:"rebate_rate"`
}

func RecycleCardConfigInfo() (RecycleCardConfig, error) {
	var recycleConfig RecycleCardConfig
	var configAllocation Config
	//err := NewConfigQuerySet(DB).NameEq(ConfigRecycleCard).One(&configAllocation)
	err := orm.Eloquent.Table("config").
		Where("name=?", ConfigRecycleCard).Find(&configAllocation).Error
	if err != nil {
		logger.Errorf("err:", err)
		return recycleConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), &recycleConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return recycleConfig, err
	}

	return recycleConfig, nil
}

func RecycleCardConfigUpdate(recycleConfig RecycleCardConfig) (RecycleCardConfig, error) {
	bytes, err := json.Marshal(recycleConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return recycleConfig, err
	}

	orm.Eloquent.Table("config").
		Where("name=?", ConfigRecycleCard).Update("Value", string(bytes))
	if err != nil {
		logger.Errorf("err:", err)
		return recycleConfig, err
	}

	return recycleConfig, nil
}

// CooperativePayInfo 支付信息
type CooperativePayInfo struct {
	CooperativeBusinessId uint32 `json:"cooperative_business_id" binding:"required"` // 合作商id
	UnionPayMerchantId    string `json:"union_pay_merchant_id" gorm:"index"`         // 聚合支付平台商户号
	WxAppId               string `json:"wx_app_id" gorm:"index"`                     // 微信小程序AppID
	WxAppMchId            string `json:"wx_app_mchId" gorm:"index"`                  // 微信支付商户号
	WxAppMchSecret        string `json:"wx_app_mchSecret" gorm:"index"`              // 微信支付商户密钥
}

// SetPayInfo 设置合作商的支付信息（聚合支付、微信支付等）
func SetPayInfo(req *CooperativeSetPayInfoReq) error {
	payInfo := CooperativePayInfo{
		CooperativeBusinessId: req.CooperativeBusinessId,
		UnionPayMerchantId:    req.UnionPayMerchantId,
		WxAppId:               req.WxAppId,
		WxAppMchId:            req.WxAppMchId,
		WxAppMchSecret:        req.WxAppMchSecret,
	}

	jPayInfo, err := json.Marshal(payInfo)
	if err != nil {
		logger.Errorf("CooperativePayInfo marshal err:", logger.Field("err", err))
		return err
	}

	var configInfo Config
	err = orm.Eloquent.Table("config").Where("name=?", ConfigCooperativePayInfo).Find(&configInfo).Error
	if err != nil {
		logger.Error("query config err:", logger.Field("err", err))
		return errors.New("操作失败:" + err.Error())
	}

	if errors.Is(err, RecordNotFound) || configInfo.ID == 0 { // 没有记录则新增
		configInfo.Name = ConfigCooperativePayInfo
		configInfo.Value = string(jPayInfo)
		err = orm.Eloquent.Create(&configInfo).Error
		if err != nil {
			logger.Errorf("create CooperativePayInfo err:", logger.Field("err", err))
			return errors.New("保存失败:" + err.Error())
		}
	} else { // 有记录则更新
		var updateConfigInfo Config
		updateConfigInfo.ID = configInfo.ID
		updateConfigInfo.Name = ConfigCooperativePayInfo
		updateConfigInfo.Value = string(jPayInfo)

		err = orm.Eloquent.Model(&Config{}).Where("id = ?", configInfo.ID).Updates(updateConfigInfo).Error
		if err != nil {
			logger.Error("update CooperativePayInfo err:", logger.Field("err", err))
			return errors.New("保存失败:" + err.Error())
		}
	}

	return nil
}

// GetPayInfo 获取合作商的支付信息（聚合支付、微信支付等）
func GetPayInfo() (*CooperativePayInfo, error) {
	payConfig := new(CooperativePayInfo)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigCooperativePayInfo).Find(&configAllocation).Error
	if err != nil {
		logger.Errorf("err:", err)
		return payConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), payConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return payConfig, err
	}

	return payConfig, nil
}

type ErpOrderShowConfig struct {
	ShowAll string `json:"show_all" binding:"required"` // 展示所有订单配置：ON-打开，OFF-关闭
}

type SystemSmsConfig struct {
	MonthFreeCount uint32 `json:"month_free_count" ` // 每月短信免费额度
}

type TestUserInfoConfig struct {
	Uid []uint32 `json:"uid" ` // 测试用户uid
}

// SetErpOrderShowConfig 设置零售订单展示配置信息
func SetErpOrderShowConfig(req *ErpOrderShowConfig) error {
	showInfo := ErpOrderShowConfig{
		ShowAll: req.ShowAll,
	}

	jShowInfo, err := json.Marshal(showInfo)
	if err != nil {
		logger.Errorf("ConfigErpOrderShowInfo marshal err:", logger.Field("err", err))
		return err
	}

	var configInfo Config
	err = orm.Eloquent.Table("config").Where("name=?", ConfigErpOrderShowInfo).Find(&configInfo).Error
	if err != nil {
		logger.Error("query config err:", logger.Field("err", err))
		return errors.New("操作失败:" + err.Error())
	}

	if errors.Is(err, RecordNotFound) || configInfo.ID == 0 { // 没有记录则新增
		configInfo.Name = ConfigErpOrderShowInfo
		configInfo.Value = string(jShowInfo)
		err = orm.Eloquent.Create(&configInfo).Error
		if err != nil {
			logger.Errorf("create ConfigErpOrderShowInfo err:", logger.Field("err", err))
			return errors.New("保存失败:" + err.Error())
		}
	} else { // 有记录则更新
		var updateConfigInfo Config
		updateConfigInfo.ID = configInfo.ID
		updateConfigInfo.Name = ConfigErpOrderShowInfo
		updateConfigInfo.Value = string(jShowInfo)

		err = orm.Eloquent.Model(&Config{}).Where("id = ?", configInfo.ID).Updates(updateConfigInfo).Error
		if err != nil {
			logger.Error("update ConfigErpOrderShowInfo err:", logger.Field("err", err))
			return errors.New("保存失败:" + err.Error())
		}
	}

	return nil
}

// GetErpOrderShowConfig 获取零售订单展示配置信息
func GetErpOrderShowConfig() (*ErpOrderShowConfig, error) {
	erpOrderShowConfig := new(ErpOrderShowConfig)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigErpOrderShowInfo).Find(&configAllocation).Error
	if err != nil {
		logger.Errorf("err:", err)
		return erpOrderShowConfig, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), erpOrderShowConfig)
	if err != nil {
		logger.Errorf("err:", err)
		return erpOrderShowConfig, err
	}

	return erpOrderShowConfig, nil
}

type DefaultUserNameAndPasswordResp struct {
	Username string `json:"username"` // 用户名
	Password string `json:"password"` // 密码
}

// GetDefaultUserNameAndPassword 获取合作商默认用户名和密码
func GetDefaultUserNameAndPassword() (*DefaultUserNameAndPasswordResp, error) {
	username, password := generateUsernameAndPassword()

	key := []byte("NfOM3p64ThVKX7Ck34R1mOeiniwuCwua")
	// 加密用户名和密码
	encryptedUsername, err := encrypt(username, key)
	if err != nil {
		fmt.Println("Error encrypting username:", err)
		return nil, err
	}

	encryptedPassword, err := encrypt(password, key)
	if err != nil {
		fmt.Println("Error encrypting password:", err)
		return nil, err
	}

	return &DefaultUserNameAndPasswordResp{
		Username: encryptedUsername,
		Password: encryptedPassword,
	}, nil
}

// 生成指定长度的随机字符串
func generateRandomString(length int) string {
	rand.Seed(time.Now().UnixNano())

	characters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	result := make([]rune, length)
	for i := range result {
		result[i] = characters[rand.Intn(len(characters))]
	}
	return string(result)
}

// 生成用户名和密码
func generateUsernameAndPassword() (string, string) {
	var username, password string
	for {
		username = generateRandomString(4)
		var count int64
		err := orm.Eloquent.Table("cooperative_business").Where("username = ?", username).Count(&count).Error
		if err == nil && count > 0 {
			continue
		}
		break
	}

	for {
		password = generateRandomString(6)
		var count int64
		err := orm.Eloquent.Table("cooperative_business").Where("password = ?", password).Count(&count).Error
		if err == nil && count > 0 {
			continue
		}
		break
	}
	return username, password
}

// 加密字符串
func encrypt(plainText string, key []byte) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 对明文进行填充
	plainBytes := []byte(plainText)
	padLen := aes.BlockSize - len(plainBytes)%aes.BlockSize
	padText := append(plainBytes, bytesRepeating(byte(padLen), padLen)...)

	// 创建一个加密分组链，使用 key 进行加密
	cipherText := make([]byte, aes.BlockSize+len(padText))
	iv := cipherText[:aes.BlockSize]
	if _, err := io.ReadFull(craned.Reader, iv); err != nil {
		return "", err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(cipherText[aes.BlockSize:], padText)

	return base64.URLEncoding.EncodeToString(cipherText), nil
}

// bytesRepeating 重复生成一个字节的切片
func bytesRepeating(b byte, count int) []byte {
	result := make([]byte, count)
	for i := 0; i < count; i++ {
		result[i] = b
	}
	return result
}

// 解密字符串
func decrypt(cipherText string, key []byte) (string, error) {
	cipherBytes, err := base64.URLEncoding.DecodeString(cipherText)
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	if len(cipherBytes) < aes.BlockSize {
		return "", fmt.Errorf("cipher text too short")
	}

	iv := cipherBytes[:aes.BlockSize]
	cipherBytes = cipherBytes[aes.BlockSize:]

	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(cipherBytes, cipherBytes)

	// 去除填充部分
	padLen := int(cipherBytes[len(cipherBytes)-1])
	if padLen < 1 || padLen > aes.BlockSize {
		return "", fmt.Errorf("invalid padding length")
	}

	return string(cipherBytes[:len(cipherBytes)-padLen]), nil
}

// GetSystemSmsConfig 获取系统每月短信限额
func GetSystemSmsConfig() (int, error) {
	smsConfig := new(SystemSmsConfig)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigSystemSmsCount).Find(&configAllocation).Error
	if err != nil {
		logger.Errorf("GetSystemSmsConfig err:", err)
		return 0, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), smsConfig)
	if err != nil {
		logger.Errorf("GetSystemSmsConfig err:", err)
		return int(smsConfig.MonthFreeCount), err
	}

	return int(smsConfig.MonthFreeCount), nil
}

// GetTestUserConfig 获取测试用户信息
func GetTestUserConfig() ([]UserInfo, error) {
	testConfig := new(TestUserInfoConfig)
	var configAllocation Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigTestUserInfo).Find(&configAllocation).Error
	if err != nil {
		logger.Errorf("GetSystemSmsConfig err:", err)
		return nil, err
	}

	err = json.Unmarshal([]byte(configAllocation.Value), testConfig)
	if err != nil {
		logger.Errorf("GetSystemSmsConfig err:", err)
		return nil, err
	}

	var users []UserInfo
	for i, item := range testConfig.Uid {
		user, _ := GetUserInfoByUid(item)
		if user.ID == 0 { // 没查到数据
			continue
		}

		user.ID = uint32(i) + 1
		user.MemberLevel = MemberLevelTest

		users = append(users, user)
	}

	return users, nil
}

type LotteryConfig struct {
	CostPerDraw    uint `json:"cost_per_draw"`   // 单次抽奖积分
	DailyLimit     uint `json:"daily_limit"`     // 每日抽奖上限
	LotteryEnabled bool `json:"lottery_enabled"` // 是否开启抽奖功能
}

func GetLotteryConfig() (*LotteryConfig, error) {
	var config Config
	err := orm.Eloquent.Table("config").Where("name=?", ConfigNameLotteryLimit).Find(&config).Error
	if err != nil {
		logger.Errorf("读取配置失败:", err)
		return nil, err
	}

	var lotteryCfg LotteryConfig
	err = json.Unmarshal([]byte(config.Value), &lotteryCfg)
	if err != nil {
		logger.Errorf("配置解析失败:", err)
		return nil, err
	}

	return &lotteryCfg, nil
}
