package usecase

import (
	errs "backend/pkg/library/errors"
	"context"
	"errors"
	"fmt"

	"backend/pkg/member/domain/entity"
	"backend/pkg/member/domain/usecase"

	"github.com/zeromicro/go-zero/core/stores/mon"
)

func (use *MemberUseCase) BindUserInfo(ctx context.Context, req usecase.CreateUserInfoRequest) error {
	// prepare 準備資料
	// 準備資料
	insert := &entity.User{
		UID:               req.UID,
		AvatarURL:         req.AvatarURL,
		FullName:          req.FullName,
		Nickname:          req.Nickname,
		GenderCode:        req.GenderCode,
		Birthdate:         req.Birthdate,
		Address:           req.Address,
		AlarmCategory:     req.AlarmCategory,
		UserStatus:        req.UserStatus,
		PreferredLanguage: req.PreferredLanguage,
		Currency:          req.Currency,
	}

	// Insert 新增
	if err := use.User.Insert(ctx, insert); err != nil {
		e := errs.DBErrorErrorL(use.Logger,
			[]errs.LogField{
				{Key: "req", Val: req},
				{Key: "func", Val: "User.Insert"},
				{Key: "err", Val: err.Error()},
			},
			"failed to binding user info").Wrap(err)

		return e
	}

	return nil
}

func (use *MemberUseCase) BindAccount(ctx context.Context, req usecase.BindingUser) (usecase.BindingUser, error) {
	// 先確定有這個Account
	_, err := use.Account.FindOneByAccount(ctx, req.LoginID)
	if err != nil {
		var e *errs.Error
		switch {
		case errors.Is(err, mon.ErrNotFound):
			e = errs.ResNotFoundError(
				fmt.Sprintf("failed to insert account: %s", req.UID),
			)
		default:
			e = errs.DBErrorErrorL(use.Logger,
				[]errs.LogField{
					{Key: "req", Val: req},
					{Key: "func", Val: "User.FindOneByAccount"},
					{Key: "err", Val: err.Error()},
				},
				"failed to find account").Wrap(err)
		}

		return usecase.BindingUser{}, e
	}

	uid := req.UID
	// 有帳號，沒UID 表示他是要產生一個新的UID，產一個給他
	if req.UID == "" {
		uid, err = use.Generate(ctx)
		if err != nil {
			// generate 裡面會產生 error
			// usecase 印出錯誤其中一個準則，在最基底的 uc 裡面印錯誤
			return usecase.BindingUser{}, err
		}
	}
	if err := use.AccountUID.Insert(ctx, &entity.AccountUID{
		LoginID: req.LoginID,
		UID:     uid,
		Type:    req.Type,
	}); err != nil {
		e := errs.DBErrorErrorL(use.Logger,
			[]errs.LogField{
				{Key: "req", Val: req},
				{Key: "func", Val: "User.Insert"},
				{Key: "err", Val: err.Error()},
			},
			"failed to bind account").Wrap(err)

		return usecase.BindingUser{}, e
	}

	return usecase.BindingUser{
		LoginID: req.LoginID,
		UID:     uid,
		Type:    req.Type,
	}, nil
}

func (use *MemberUseCase) BindVerifyEmail(ctx context.Context, uid, email string) error {
	err := use.User.UpdateEmailVerifyStatus(ctx, uid, email)
	if err != nil {
		e := errs.DBErrorError(
			fmt.Sprintf("failed to Binding uid: %s, email: %s", uid, email),
		)

		return e
	}

	return nil
}

func (use *MemberUseCase) BindVerifyPhone(ctx context.Context, uid, phone string) error {
	err := use.User.UpdatePhoneVerifyStatus(ctx, uid, phone)
	if err != nil {
		e := errs.DBErrorErrorL(use.Logger,
			[]errs.LogField{
				{Key: "req", Val: uid},
				{Key: "func", Val: "User.UpdatePhoneVerifyStatus"},
				{Key: "err", Val: err.Error()},
			},
			fmt.Sprintf("failed to Binding uid: %s, phone: %s", uid, phone),
		)

		return e
	}

	return nil
}
