package operator

import (
	"context"

	"github.com/pingcap/log"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/db"
	"github.com/pingcap-inc/clinic/pkg/db/model"
	"github.com/pingcap-inc/clinic/tools/cleanup_user/feishuapi"
)

type Operator struct {
	// hrEmployeeDao *HREmployeeDao
	feishuAPICli *feishuapi.Client
}

func NewOperator(apiCli *feishuapi.Client) *Operator {
	return &Operator{
		// hrEmployeeDao: dao,
		feishuAPICli: apiCli,
	}
}

func (o *Operator) Run() error {
	log.Info("run operator to delete resigned user")
	var notExistUsers []db.User
	users, err := model.GetAllInternalUsers()
	if err != nil {
		return err
	}

	// get not existed in pingcap group
	for _, u := range users {
		existed, err := o.isExistInPingCAP(u.UserName)
		if err != nil {
			// do not abort the process on error
			// consider user is still exist if error occurs
			log.Warn("check user failed", zap.Error(err))
		} else if !existed {
			notExistUsers = append(notExistUsers, u)
		}
	}
	// delete
	return o.deleteUsers(notExistUsers)
}

func (o *Operator) deleteUsers(us []db.User) error {
	for _, u := range us {
		// log as warning for audit
		log.Warn("start delete resigned user", zap.String("email", u.Email), zap.String("username", u.UserName))
		err := o.deleteUser(u)
		if err != nil {
			log.Error("delete user failed", zap.Error(err), zap.Any("User", u.UserName))
		}
	}
	return nil
}

func (o *Operator) deleteUser(u db.User) error {
	// clear cred and user
	err := model.DeleteCredentialByUserID(u.ID)
	if err != nil {
		log.Error("delete cred by user id failed",
			zap.Uint("id", u.ID),
			zap.Error(err))
		return err
	}

	err = model.DeleteUserByID(u.ID)
	if err != nil {
		log.Error("delete user by id failed",
			zap.Uint("id", u.ID),
			zap.Error(err))
		return err
	}

	return nil
}

func (o *Operator) isExistInPingCAP(email string) (bool, error) {
	ctx := context.Background()
	openID, found, err := o.feishuAPICli.GetUserID(ctx, email)
	if err != nil {
		log.Error("get user open id failed", zap.Error(err))
		return false, err
	}
	if !found {
		log.Warn("user open id is not found", zap.String("email", email))
		return false, nil
	}
	data, err := o.feishuAPICli.GetUserInfo(ctx, openID)
	if err != nil {
		log.Error("get user info failed", zap.Error(err))
		return false, err
	}
	return !data.IsResigned(), nil
}
