package logic

import (
	"context"
	"encoding/json"
	"errors"
	"juwan-backend/app/snowflake/rpc/snowflake"
	"juwan-backend/app/user_verifications/rpc/internal/models"
	"juwan-backend/app/user_verifications/rpc/internal/models/schema"
	"juwan-backend/app/user_verifications/rpc/internal/models/userverifications"
	"juwan-backend/app/user_verifications/rpc/internal/svc"
	"juwan-backend/app/user_verifications/rpc/pb"
	"juwan-backend/app/users/rpc/usercenter"
	"slices"

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

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

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

func (l *AddOrUpdateUserVerificationsLogic) AddOrUpdateUserVerifications(in *pb.AddOrUpdateUserVerificationsReq) (*pb.AddOrUpdateUserVerificationsResp, error) {
	NotFoundError := &models.NotFoundError{}
	var materials schema.MaterialStruct

	uv, vErr := l.svcCtx.UserVeriModelRO.Query().
		Where(
			userverifications.UserIDEQ(in.UserId),
			userverifications.RoleEQ(in.Role),
			userverifications.StatusNEQ("rejected"),
		).
		First(l.ctx)
	if vErr != nil && !errors.As(vErr, &NotFoundError) {
		logx.Errorf("add or update user verifications: get user err:%v", vErr)
		return nil, errors.New("")
	}

	isRole, err := l.checkIsRole(in.UserId, in.Role)

	if err != nil {
		logx.Errorf("add or update user verifications: check user err:%v", err)
		return nil, errors.New("check user role failed")
	}
	if isRole {
		return nil, errors.New("user already has the role")
	}

	jsonErr := json.Unmarshal([]byte(in.Material), &materials)
	if jsonErr != nil {
		logx.Errorf("add or update user verifications: marshal materials err:%v", jsonErr)
		return nil, errors.New("invalid materials")
	}

	idResp, rpcErr := l.svcCtx.SnowflakeRpc.NextId(l.ctx, &snowflake.NextIdReq{})
	if errors.As(vErr, &NotFoundError) {
		if rpcErr != nil {
			logx.Errorf("add or update user verifications: get next id err:%v", rpcErr)
			return nil, errors.New("generate id failed: ")
		}

		uv, err = l.svcCtx.UserVeriModelRW.Create().
			SetID(idResp.Id).
			SetUserID(in.UserId).
			SetRole(in.Role).
			SetMaterials(materials).
			SetRejectReason("").
			SetReviewedBy(0).
			Save(l.ctx)
		if err != nil {
			logx.Errorf("add or update user verifications: create user verifications err:%v", err)
			return nil, errors.New("create user verifications failed")
		}
	} else {
		uv, err = uv.Update().
			SetRole(in.Role).
			SetMaterials(materials).
			Save(l.ctx)
		if err != nil {
			logx.Errorf("add or update user verifications: update user verifications err:%v", err)
			return nil, errors.New("update user verifications failed")
		}
	}

	return &pb.AddOrUpdateUserVerificationsResp{
		Success: true,
	}, nil
}

func (l *AddOrUpdateUserVerificationsLogic) checkIsRole(userid int64, role string) (bool, error) {
	user, err := l.svcCtx.UserRpc.GetUsersById(l.ctx, &usercenter.GetUsersByIdReq{
		Id: userid,
	})
	logx.Debug("checkIsRole user:", user)
	if err != nil {
		return false, err
	}
	logx.Debug("checkIsRole user verified roles:", user.Users.VerifiedRoles)
	if slices.Contains(user.Users.VerifiedRoles, role) {
		return true, nil
	}
	return false, nil
}
