package agent

import (
	"context"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"
	"strings"
	"bdqr-server/app/main/model"
	"bdqr-server/common/ctxdata"
	"bdqr-server/common/globalkey"
	"bdqr-server/common/tool"
	"bdqr-server/common/xerr"
	"bdqr-server/pkg/lzkit/crypto"

	"github.com/Masterminds/squirrel"
	"github.com/pkg/errors"

	"bdqr-server/app/main/api/internal/svc"
	"bdqr-server/app/main/api/internal/types"

	"github.com/google/uuid"
	"github.com/zeromicro/go-zero/core/logx"
)

type GeneratingLinkLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGeneratingLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GeneratingLinkLogic {
	return &GeneratingLinkLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GeneratingLinkLogic) GeneratingLink(req *types.AgentGeneratingLinkReq) (resp *types.AgentGeneratingLinkResp, err error) {
	userID, err := ctxdata.GetUidFromCtx(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成推广链接失败, %v", err)
	}

	// 1. 获取代理信息
	agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
	}

	// 2. 获取产品配置（必须存在）
	productConfig, err := l.svcCtx.AgentProductConfigModel.FindOneByProductId(l.ctx, req.ProductId)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "产品配置不存在, productId: %d，请先在后台配置产品价格参数", req.ProductId)
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品配置失败, productId: %d, %v", req.ProductId, err)
	}

	// 3. 获取等级加成配置
	levelBonus, err := l.getLevelBonus(agentModel.Level)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取等级加成配置失败, %v", err)
	}

    basePrice := productConfig.BasePrice
    actualBasePrice := basePrice + float64(levelBonus)
    systemMaxPrice := productConfig.SystemMaxPrice
    upliftAmount, err := l.getLevelMaxUpliftAmount(agentModel.Level)
    if err != nil {
        return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取等级上调金额失败, %v", err)
    }
    levelMaxPrice := systemMaxPrice + upliftAmount
    if req.SetPrice < actualBasePrice || req.SetPrice > levelMaxPrice {
        return nil, errors.Wrapf(xerr.NewErrMsg("设定价格必须在 %.2f 到 %.2f 之间"), "设定价格必须在 %.2f 到 %.2f 之间", actualBasePrice, levelMaxPrice)
    }

	// 6. 检查是否已存在相同的链接（同一代理、同一产品、同一价格）
	builder := l.svcCtx.AgentLinkModel.SelectBuilder().Where(squirrel.And{
		squirrel.Eq{"agent_id": agentModel.Id},
		squirrel.Eq{"product_id": req.ProductId},
		squirrel.Eq{"set_price": req.SetPrice},
		squirrel.Eq{"del_state": globalkey.DelStateNo},
	})

	existingLinks, err := l.svcCtx.AgentLinkModel.FindAll(l.ctx, builder, "")
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询推广链接失败, %v", err)
	}

	if len(existingLinks) > 0 {
		// 已存在，检查是否有短链，如果没有则生成
		targetPath := req.TargetPath
		if targetPath == "" {
			targetPath = "/agent/promotionInquire/"
		}
		shortLink, err := l.getOrCreateShortLink(1, existingLinks[0].Id, "", existingLinks[0].LinkIdentifier, "", targetPath)
		if err != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取或创建短链失败, %v", err)
		}
		return &types.AgentGeneratingLinkResp{
			LinkIdentifier: existingLinks[0].LinkIdentifier,
			FullLink:       shortLink,
		}, nil
	}

	// 7. 生成推广链接标识
	var agentIdentifier types.AgentIdentifier
	agentIdentifier.AgentID = agentModel.Id
	agentIdentifier.ProductID = req.ProductId
	agentIdentifier.SetPrice = req.SetPrice
	agentIdentifierByte, err := json.Marshal(agentIdentifier)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "序列化标识失败, %v", err)
	}

	// 8. 加密链接标识
	secretKey := l.svcCtx.Config.Encrypt.SecretKey
	key, decodeErr := hex.DecodeString(secretKey)
	if decodeErr != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取AES密钥失败: %+v", decodeErr)
	}

	encrypted, err := crypto.AesEncryptURL(agentIdentifierByte, key)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密链接标识失败, %v", err)
	}

	// 9. 保存推广链接
	agentLink := &model.AgentLink{
		// Id:              uuid.NewString(),
		AgentId:         agentModel.Id,
		UserId:          userID,
		ProductId:       req.ProductId,
		LinkIdentifier:  encrypted,
		SetPrice:        req.SetPrice,
		ActualBasePrice: actualBasePrice,
	}

	_, err = l.svcCtx.AgentLinkModel.Insert(l.ctx, nil, agentLink)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "保存推广链接失败, %v", err)
	}

	linkId := agentLink.Id

	// 使用默认target_path（如果未提供）
	targetPath := req.TargetPath
	if targetPath == "" {
		targetPath = "/agent/promotionInquire/"
	}

	// 生成短链（类型：1=推广报告）
	shortLink, err := l.createShortLink(1, linkId, "", encrypted, "", targetPath)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成短链失败, %v", err)
	}

	return &types.AgentGeneratingLinkResp{
		LinkIdentifier: encrypted,
		FullLink:       shortLink,
	}, nil
}

// getLevelBonus 获取等级加成（从配置表读取）
func (l *GeneratingLinkLogic) getLevelBonus(level int64) (int64, error) {
	var configKey string
	switch level {
	case 1: // 普通
		configKey = "level_1_bonus"
	case 2: // 黄金
		configKey = "level_2_bonus"
	case 3: // 钻石
		configKey = "level_3_bonus"
	default:
		return 0, nil
	}

	config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, configKey)
	if err != nil {
		// 配置不存在时返回默认值
		l.Errorf("获取等级加成配置失败, level: %d, key: %s, err: %v，使用默认值", level, configKey, err)
		switch level {
		case 1:
			return 6, nil
		case 2:
			return 3, nil
		case 3:
			return 0, nil
		}
		return 0, nil
	}

	value, err := strconv.ParseFloat(config.ConfigValue, 64)
	if err != nil {
		return 0, errors.Wrapf(err, "解析配置值失败, key: %s, value: %s", configKey, config.ConfigValue)
	}
	return int64(value), nil
}

func (l *GeneratingLinkLogic) getLevelMaxUpliftAmount(level int64) (float64, error) {
    var key string
    switch level {
    case 2:
        key = "gold_max_uplift_amount"
    case 3:
        key = "diamond_max_uplift_amount"
    default:
        return 0, nil
    }
    config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
    if err != nil {
        return 0, nil
    }
    v, err := strconv.ParseFloat(config.ConfigValue, 64)
    if err != nil {
        return 0, nil
    }
    if v < 0 {
        return 0, nil
    }
    return v, nil
}

// getOrCreateShortLink 获取或创建短链
// type: 1=推广报告(promotion), 2=邀请好友(invite)
// linkId: 推广链接ID（仅推广报告使用）
// inviteCodeId: 邀请码ID（仅邀请好友使用）
// linkIdentifier: 推广链接标识（仅推广报告使用）
// inviteCode: 邀请码（仅邀请好友使用）
// targetPath: 目标地址（前端传入）
func (l *GeneratingLinkLogic) getOrCreateShortLink(linkType int64, linkId, inviteCodeId string, linkIdentifier, inviteCode, targetPath string) (string, error) {
	// 先查询是否已存在短链
	var existingShortLink *model.AgentShortLink
	var err error

	if linkType == 1 {
		// 推广报告类型，使用link_id查询
		if linkId != "" {
			existingShortLink, err = l.svcCtx.AgentShortLinkModel.FindOneByLinkIdTypeDelState(l.ctx, sql.NullString{String: linkId, Valid: true}, linkType, globalkey.DelStateNo)
		}
	} else {
		// 邀请好友类型，使用invite_code_id查询
		if inviteCodeId != "" {
			existingShortLink, err = l.svcCtx.AgentShortLinkModel.FindOneByInviteCodeIdTypeDelState(l.ctx, sql.NullString{String: inviteCodeId, Valid: true}, linkType, globalkey.DelStateNo)
		}
	}

	if err == nil && existingShortLink != nil {
		// 已存在短链，直接返回
		return l.buildShortLinkURL(existingShortLink.ShortCode), nil
	}

	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return "", errors.Wrapf(err, "查询短链失败")
	}

	// 不存在，创建新的短链
	return l.createShortLink(linkType, linkId, inviteCodeId, linkIdentifier, inviteCode, targetPath)
}

// createShortLink 创建短链
// type: 1=推广报告(promotion), 2=邀请好友(invite)
func (l *GeneratingLinkLogic) createShortLink(linkType int64, linkId, inviteCodeId string, linkIdentifier, inviteCode, targetPath string) (string, error) {
	promotionConfig := l.svcCtx.Config.Promotion

	// 如果没有配置推广域名，返回空字符串（保持向后兼容）
	if promotionConfig.PromotionDomain == "" {
		l.Errorf("推广域名未配置，返回空链接")
		return "", nil
	}

	// 验证target_path
	if targetPath == "" {
		return "", errors.Wrapf(xerr.NewErrMsg("目标地址不能为空"), "")
	}

	// 对于推广报告类型，将 linkIdentifier 拼接到 target_path
	if linkType == 1 && linkIdentifier != "" {
		// 如果 target_path 以 / 结尾，直接拼接 linkIdentifier
		if strings.HasSuffix(targetPath, "/") {
			targetPath = targetPath + url.QueryEscape(linkIdentifier)
		} else {
			// 否则在末尾添加 / 再拼接
			targetPath = targetPath + "/" + url.QueryEscape(linkIdentifier)
		}
	}

	// 生成短链标识（6位随机字符串，大小写字母+数字）
	var shortCode string
	maxRetries := 10 // 最大重试次数
	for retry := 0; retry < maxRetries; retry++ {
		shortCode = tool.Krand(6, tool.KC_RAND_KIND_ALL)
		// 检查短链标识是否已存在
		_, err := l.svcCtx.AgentShortLinkModel.FindOneByShortCodeDelState(l.ctx, shortCode, globalkey.DelStateNo)
		if err != nil {
			if errors.Is(err, model.ErrNotFound) {
				// 短链标识不存在，可以使用
				break
			}
			return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查短链标识失败, %v", err)
		}
		// 短链标识已存在，继续生成
		if retry == maxRetries-1 {
			return "", errors.Wrapf(xerr.NewErrMsg("生成短链失败，请重试"), "")
		}
	}

	// 创建短链记录
	shortLink := &model.AgentShortLink{
		Id:              uuid.NewString(),
		Type:            linkType,
		ShortCode:       shortCode,
		TargetPath:      targetPath,
		PromotionDomain: promotionConfig.PromotionDomain,
	}

	// 根据类型设置对应字段
	if linkType == 1 {
		// 推广报告类型
		shortLink.LinkId = sql.NullString{String: linkId, Valid: linkId != ""}
		if linkIdentifier != "" {
			shortLink.LinkIdentifier = sql.NullString{String: linkIdentifier, Valid: true}
		}
	} else if linkType == 2 {
		// 邀请好友类型
		shortLink.InviteCodeId = sql.NullString{String: inviteCodeId, Valid: inviteCodeId != ""}
		if inviteCode != "" {
			shortLink.InviteCode = sql.NullString{String: inviteCode, Valid: true}
		}
	}
	_, err := l.svcCtx.AgentShortLinkModel.Insert(l.ctx, nil, shortLink)
	if err != nil {
		return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "保存短链失败, %v", err)
	}

	return l.buildShortLinkURL(shortCode), nil
}

// buildShortLinkURL 构建短链URL
func (l *GeneratingLinkLogic) buildShortLinkURL(shortCode string) string {
	promotionConfig := l.svcCtx.Config.Promotion
	return fmt.Sprintf("%s/s/%s", promotionConfig.PromotionDomain, shortCode)
}
