package service

import (
	"context"
	"database/sql"
	"bdqr-server/app/main/api/internal/config"
	"bdqr-server/app/main/model"
	"bdqr-server/common/ctxdata"
	jwtx "bdqr-server/common/jwt"
	"bdqr-server/common/xerr"

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

type UserService struct {
	Config        *config.Config
	userModel     model.UserModel
	userAuthModel model.UserAuthModel
	agentModel    model.AgentModel
}

// NewUserService 创建UserService实例
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, agentModel model.AgentModel) *UserService {
	return &UserService{
		Config:        config,
		userModel:     userModel,
		userAuthModel: userAuthModel,
		agentModel:    agentModel,
	}
}

// GenerateUUIDUserId 生成UUID用户ID
func (s *UserService) GenerateUUIDUserId(ctx context.Context) (string, error) {
	id := uuid.NewString()
	return id, nil
}

// RegisterUUIDUser 注册UUID用户，返回用户ID
func (s *UserService) RegisterUUIDUser(ctx context.Context) (string, error) {
	// 生成UUID
	uuidStr, err := s.GenerateUUIDUserId(ctx)
	if err != nil {
		return "", err
	}

	var userId string
	err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
		user := &model.User{Id: uuid.NewString()}
		if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
			return userInsertErr
		}
		userId = user.Id
		userAuth := &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeUUID, AuthKey: uuidStr}
		_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, userAuth)
		return userAuthInsertErr
	})
	if err != nil {
		return "", err
	}

	return userId, nil
}

// GetUserType 根据user.Mobile字段动态计算用户类型
// 如果有mobile，则为正式用户(UserTypeNormal)，否则为临时用户(UserTypeTemp)
func (s *UserService) GetUserType(ctx context.Context, userID string) (int64, error) {
	user, err := s.userModel.FindOne(ctx, userID)
	if err != nil {
		return 0, err
	}
	if user.Mobile.Valid && user.Mobile.String != "" {
		return model.UserTypeNormal, nil
	}
	return model.UserTypeTemp, nil
}

// GeneralUserToken 生成用户token（动态计算userType）
func (s *UserService) GeneralUserToken(ctx context.Context, userID string) (string, error) {
	platform, err := ctxdata.GetPlatformFromCtx(ctx)
	if err != nil {
		return "", err
	}
	var isAgent int64
	var agentID string
	var authType string
	var authKey string
	// 获取用户信息，根据mobile字段动态计算userType
	user, err := s.userModel.FindOne(ctx, userID)
	if err != nil {
		return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err)
	}

	// 根据mobile判断用户类型
	var userType int64
	if user.Mobile.Valid && user.Mobile.String != "" {
		userType = model.UserTypeNormal
	} else {
		userType = model.UserTypeTemp
	}
	agent, err := s.agentModel.FindOneByUserId(ctx, userID)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新token, 获取用户代理信息失败: %v", err)
	}
	if agent != nil {
		agentID = agent.Id
		isAgent = model.AgentStatusYes
	}
	platAuthType := s.getAuthTypeByPlatform(platform)
	ua, err := s.userAuthModel.FindOneByUserIdAuthType(ctx, userID, platAuthType)
	if err == nil && ua != nil {
		authType = ua.AuthType
		authKey = ua.AuthKey
	}
	token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{
		UserId:   userID,
		AgentId:  agentID,
		Platform: platform,
		UserType: userType,
		IsAgent:  isAgent,
		AuthType: authType,
		AuthKey:  authKey,
	}, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire)
	if generaErr != nil {
		return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %s", userID)
	}
	return token, nil
}

func (s *UserService) getAuthTypeByPlatform(platform string) string {
	switch platform {
	case model.PlatformWxMini:
		return model.UserAuthTypeWxMiniOpenID
	case model.PlatformWxH5:
		return model.UserAuthTypeWxh5OpenID
	case model.PlatformH5, model.PlatformApp:
		return model.UserAuthTypeUUID
	default:
		return model.UserAuthTypeUUID
	}
}

// RegisterUser 注册用户，返回用户ID
// 只负责创建新用户（手机号不存在时），不处理合并逻辑
// 如果有临时用户（claims），会将临时用户的认证绑定到新用户
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, error) {
	// 检查手机号是否已存在
	user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true})
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return "", err
	}
	if user != nil {
		return "", errors.New("用户已注册")
	}

	// 获取当前登录态（可能为空）
	claims, err := ctxdata.GetClaimsFromCtx(ctx)
	if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
		return "", err
	}

	var userId string
	err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 创建新用户
		user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}}
		if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
			return userInsertErr
		}
		userId = user.Id

		// 创建 mobile 认证
		_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{
			Id:       uuid.NewString(),
			UserId:   userId,
			AuthType: model.UserAuthTypeMobile,
			AuthKey:  mobile,
		})
		if userAuthInsertErr != nil {
			return userAuthInsertErr
		}

		// 如果有临时用户，将临时用户的认证绑定到新用户
		if claims != nil {
			// 检查临时用户是否已有该认证类型
			existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
			if err != nil && !errors.Is(err, model.ErrNotFound) {
				return err
			}
			// 如果认证不存在，创建新的认证绑定
			if existingAuth == nil {
				_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
					Id:       uuid.NewString(),
					UserId:   userId,
					AuthType: claims.AuthType,
					AuthKey:  claims.AuthKey,
				})
				if err != nil {
					return err
				}
			} else if existingAuth.UserId != userId {
				// 如果认证已存在但属于其他用户，迁移到新用户
				existingAuth.UserId = userId
				if _, err := s.userAuthModel.Update(ctx, session, existingAuth); err != nil {
					return err
				}
			}
		}

		return nil
	})
	if err != nil {
		return "", err
	}
	return userId, nil
}

// TempUserBindUser 临时用户绑定用户（添加mobile使其变为正式用户）
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID string) error {
	claims, err := ctxdata.GetClaimsFromCtx(ctx)
	if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
		return err
	}

	if claims == nil {
		return errors.New("无临时用户")
	}

	// 检查当前用户是否已经绑定了mobile（根据mobile判断，而不是userType）
	tempUser, err := s.userModel.FindOne(ctx, claims.UserId)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return err
	}
	if tempUser != nil && tempUser.Mobile.Valid && tempUser.Mobile.String != "" {
		return errors.New("临时用户已注册")
	}

	existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
	if err != nil && !errors.Is(err, model.ErrNotFound) {
		return err
	}
	if existingAuth != nil {
		return errors.New("临时用户已注册")
	}

	if session == nil {
		err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
			_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
			if err != nil {
				return err
			}
			return nil
		})
		if err != nil {
			return err
		}
		return nil
	} else {
		_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
		if err != nil {
			return err
		}
		return nil
	}
}
