package agent

import (
	"context"
	"database/sql"
	"fmt"
	"os"
	"strconv"
	"time"
	"qnc-server/app/main/model"
	"qnc-server/common/ctxdata"
	"qnc-server/common/globalkey"
	"qnc-server/common/xerr"
	"qnc-server/pkg/lzkit/crypto"

	"github.com/google/uuid"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/stores/redis"
	"github.com/zeromicro/go-zero/core/stores/sqlx"

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

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

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

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

func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *types.AgentApplyResp, err error) {
	claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
	if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请失败, %v", err)
	}

	secretKey := l.svcCtx.Config.Encrypt.SecretKey
	encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
	}

	if req.Referrer == "" {
		return nil, errors.Wrapf(xerr.NewErrMsg("请填写邀请信息"), "")
	}
	// 2. 校验验证码（开发环境下跳过验证码校验）
	if os.Getenv("ENV") != "development" {
		redisKey := fmt.Sprintf("%s:%s", "agentApply", encryptedMobile)
		cacheCode, err := l.svcCtx.Redis.Get(redisKey)
		if err != nil {
			if errors.Is(err, redis.Nil) {
				return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "")
			}
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "读取验证码失败, %v", err)
		}
		if cacheCode != req.Code {
			return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "")
		}
	}

	var userID string
	transErr := l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
		// 1. 处理用户注册/绑定
		user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
		if findUserErr != nil && !errors.Is(findUserErr, model.ErrNotFound) {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败, %v", findUserErr)
		}

		if user == nil {
			// 用户不存在，注册新用户
			if claims != nil && claims.UserType == model.UserTypeNormal {
				return errors.Wrapf(xerr.NewErrMsg("当前用户已注册，请输入注册的手机号"), "")
			}
			userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
			if err != nil {
				return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "注册用户失败: %v", err)
			}
		} else {
			// 用户已存在
			if claims != nil && claims.UserType == model.UserTypeTemp {
				// 临时用户，检查手机号是否已绑定其他微信号
				userAuth, findUserAuthErr := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, user.Id, claims.AuthType)
				if findUserAuthErr != nil && !errors.Is(findUserAuthErr, model.ErrNotFound) {
					return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户认证失败, %v", findUserAuthErr)
				}
				if userAuth != nil && userAuth.AuthKey != claims.AuthKey {
					return errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "")
				}
				// 临时用户，转为正式用户
				err = l.svcCtx.UserService.TempUserBindUser(l.ctx, session, user.Id)
				if err != nil {
					return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定用户失败: %v", err)
				}
			}
			userID = user.Id
		}

		// 3. 检查是否已是代理
		existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(transCtx, userID)
		if err != nil && !errors.Is(err, model.ErrNotFound) {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
		}
		if existingAgent != nil {
			return errors.Wrapf(xerr.NewErrMsg("您已经是代理"), "")
		}

		var inviteCodeModel *model.AgentInviteCode
		var parentAgentId string
		var targetLevel int64

		inviteCodeModel, err = l.svcCtx.AgentInviteCodeModel.FindOneByCode(transCtx, req.Referrer)
		if err != nil && !errors.Is(err, model.ErrNotFound) {
			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询邀请码失败, %v", err)
		}
		if inviteCodeModel != nil {
			if inviteCodeModel.Status != 0 {
				if inviteCodeModel.Status == 1 {
					return errors.Wrapf(xerr.NewErrMsg("邀请码已使用"), "")
				}
				return errors.Wrapf(xerr.NewErrMsg("邀请码已失效"), "")
			}
			if inviteCodeModel.ExpireTime.Valid && inviteCodeModel.ExpireTime.Time.Before(time.Now()) {
				return errors.Wrapf(xerr.NewErrMsg("邀请码已过期"), "")
			}
			targetLevel = inviteCodeModel.TargetLevel
			if inviteCodeModel.AgentId.Valid {
				parentAgentId = inviteCodeModel.AgentId.String
			}
		} else {
			if codeVal, parseErr := strconv.ParseInt(req.Referrer, 10, 64); parseErr == nil && codeVal > 0 {
				parentAgent, err := l.findAgentByCode(transCtx, codeVal)
				if err != nil {
					return err
				}
				parentAgentId = parentAgent.Id
				targetLevel = 1
			} else {
				encRefMobile, _ := crypto.EncryptMobile(req.Referrer, l.svcCtx.Config.Encrypt.SecretKey)
				agents, findErr := l.svcCtx.AgentModel.FindAll(transCtx, l.svcCtx.AgentModel.SelectBuilder().Where("mobile = ? AND del_state = ?", encRefMobile, globalkey.DelStateNo).Limit(1), "")
				if findErr != nil {
					return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询上级代理失败, %v", findErr)
				}
				if len(agents) == 0 {
					return errors.Wrapf(xerr.NewErrMsg("邀请信息无效"), "")
				}
				parentAgentId = agents[0].Id
				targetLevel = 1
			}
		}

		// 4.5 创建代理记录
		newAgent := &model.Agent{
			Id:     uuid.NewString(),
			UserId: userID,
			Level:  targetLevel,
			Mobile: encryptedMobile,
		}
		if req.Region != "" {
			newAgent.Region = sql.NullString{String: req.Region, Valid: true}
		}

		// 4.6 处理上级关系
		if parentAgentId != "" {
			// 代理发放的邀请码，成为该代理的下级
			parentAgent, err := l.svcCtx.AgentModel.FindOne(transCtx, parentAgentId)
			if err != nil {
				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询上级代理失败, %v", err)
			}

			// 验证关系是否允许
			if newAgent.Level > parentAgent.Level {
				return errors.Wrapf(xerr.NewErrMsg("代理等级不能高于上级代理"), "")
			}

			// 查找团队首领
			teamLeaderId, err := l.findTeamLeader(transCtx, parentAgent.Id)
			if err != nil {
				return errors.Wrapf(err, "查找团队首领失败")
			}
			if teamLeaderId != "" {
				newAgent.TeamLeaderId = sql.NullString{String: teamLeaderId, Valid: true}
			}

			newAgent.AgentCode = 0
			_, err = l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
			if err != nil {
				return errors.Wrapf(err, "创建代理记录失败")
			}
			// 已设置newAgent.Id为UUID

			// 建立关系
			relation := &model.AgentRelation{
				Id:           uuid.NewString(),
				ParentId:     parentAgent.Id,
				ChildId:      newAgent.Id,
				RelationType: 1,
			}
			if _, err := l.svcCtx.AgentRelationModel.Insert(transCtx, session, relation); err != nil {
				return errors.Wrapf(err, "建立代理关系失败")
			}
		} else {
			// 平台发放的钻石邀请码，独立成团队
			if targetLevel == 3 {
				newAgent.AgentCode = 0
				_, err = l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
				if err != nil {
					return errors.Wrapf(err, "创建代理记录失败")
				}
				// 设置自己为团队首领
				newAgent.TeamLeaderId = sql.NullString{String: newAgent.Id, Valid: true}
				if err := l.svcCtx.AgentModel.UpdateInTransaction(transCtx, session, newAgent); err != nil {
					return errors.Wrapf(err, "更新团队首领失败")
				}
			} else {
				newAgent.AgentCode = 0
				_, err = l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
				if err != nil {
					return errors.Wrapf(err, "创建代理记录失败")
				}
			}
		}

		// 4.7 初始化钱包
		wallet := &model.AgentWallet{
			Id:      uuid.NewString(),
			AgentId: newAgent.Id,
		}
		if _, err := l.svcCtx.AgentWalletModel.Insert(transCtx, session, wallet); err != nil {
			return errors.Wrapf(err, "初始化钱包失败")
		}

		// 4.8 更新邀请码状态
		// 钻石级别的邀请码只能使用一次，使用后立即失效
		// 普通级别的邀请码可以无限使用，不更新状态
		if targetLevel == 3 {
			// 钻石邀请码：使用后失效
			inviteCodeModel.Status = 1 // 已使用（使用后立即失效）
		}
		// 记录使用信息（用于统计，普通邀请码可以多次使用）
		inviteCodeModel.UsedUserId = sql.NullString{String: userID, Valid: true}
		if inviteCodeModel != nil {
			inviteCodeModel.UsedAgentId = sql.NullString{String: newAgent.Id, Valid: true}
			inviteCodeModel.UsedTime = sql.NullTime{Time: time.Now(), Valid: true}
			if err := l.svcCtx.AgentInviteCodeModel.UpdateWithVersion(transCtx, session, inviteCodeModel); err != nil {
				return errors.Wrapf(err, "更新邀请码状态失败")
			}
		}

		// 4.9 记录邀请码使用历史（用于统计和查询）
		usage := &model.AgentInviteCodeUsage{
			Id:           uuid.NewString(),
			InviteCodeId: inviteCodeModel.Id,
			Code:         inviteCodeModel.Code,
			UserId:       userID,
			AgentId:      newAgent.Id,
			AgentLevel:   targetLevel,
			UsedTime:     time.Now(),
		}
		if _, err := l.svcCtx.AgentInviteCodeUsageModel.Insert(transCtx, session, usage); err != nil {
			return errors.Wrapf(err, "记录邀请码使用历史失败")
		}

		return nil
	})

	if transErr != nil {
		return nil, transErr
	}

	// 6. 生成并返回token
	token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成token失败: %v", err)
	}

	now := time.Now().Unix()
	agent, _ := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
	var code int64
	if agent != nil {
		code = agent.AgentCode
	}
	return &types.AgentApplyResp{
		AccessToken:  token,
		AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
		RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
		AgentCode:    code,
	}, nil
}

func (l *ApplyForAgentLogic) findAgentByCode(ctx context.Context, code int64) (*model.Agent, error) {
	builder := l.svcCtx.AgentModel.SelectBuilder().Where("agent_code = ? AND del_state = ?", code, globalkey.DelStateNo).Limit(1)
	agents, err := l.svcCtx.AgentModel.FindAll(ctx, builder, "")
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询上级代理失败, %v", err)
	}
	if len(agents) == 0 {
		return nil, errors.Wrapf(xerr.NewErrMsg("上级邀请码不存在"), "")
	}
	return agents[0], nil
}

func (l *ApplyForAgentLogic) allocateAgentCode(ctx context.Context, session sqlx.Session) (int64, error) {
	builder := l.svcCtx.AgentModel.SelectBuilder().OrderBy("agent_code DESC").Limit(1)
	rows, err := l.svcCtx.AgentModel.FindAll(ctx, builder, "")
	if err != nil {
		return 0, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理编码失败, %v", err)
	}
	var next int64 = 16800
	if len(rows) > 0 && rows[0].AgentCode > 0 {
		next = rows[0].AgentCode + 1
	}
	return next, nil
}

// findTeamLeader 查找团队首领（钻石代理）
func (l *ApplyForAgentLogic) findTeamLeader(ctx context.Context, agentId string) (string, error) {
	currentId := agentId
	maxDepth := 100
	depth := 0

	for depth < maxDepth {
		builder := l.svcCtx.AgentRelationModel.SelectBuilder().
			Where("child_id = ? AND relation_type = ? AND del_state = ?", currentId, 1, 0)
		relations, err := l.svcCtx.AgentRelationModel.FindAll(ctx, builder, "")
		if err != nil {
			return "", err
		}
		if len(relations) == 0 {
			agent, err := l.svcCtx.AgentModel.FindOne(ctx, currentId)
			if err != nil {
				return "", err
			}
			if agent.Level == 3 {
				return agent.Id, nil
			}
			return "", nil
		}

		parentAgent, err := l.svcCtx.AgentModel.FindOne(ctx, relations[0].ParentId)
		if err != nil {
			return "", err
		}

		if parentAgent.Level == 3 {
			return parentAgent.Id, nil
		}

		currentId = parentAgent.Id
		depth++
	}

	return "", nil
}
