package service

import (
	"context"
	"fmt"
	"os"
	"strings"

	authingmodel "github.com/Authing/authing-go-sdk/lib/model"
	"github.com/spf13/viper"
	admin "google.golang.org/api/admin/directory/v1"

	"github.com/pingcap-inc/it-automation/internal/sync-google-email/store/mysql"
	"github.com/pingcap-inc/it-automation/pkg/log"
	"github.com/pingcap-inc/it-automation/pkg/provider/authing"
	"github.com/pingcap-inc/it-automation/pkg/provider/google"
)

const (
	Rename      = "Rename:"
	Delete      = "Delete:"
	DeleteEmail = "delete-"
	Deprecate   = "Deprecate:"
)

func (d *sgeService) DeptCompare(ctx context.Context) {
	log.L(ctx).Info("Start to compare dept")

	userEmail := "liuy@pingcap.com"
	serviceAccountFile := viper.GetString("google.service-account")
	adminScope := []string{
		admin.AdminDirectoryGroupMemberScope,
		admin.AdminDirectoryGroupScope,
	}
	serviceAccount, err := os.ReadFile(serviceAccountFile)
	if err != nil {
		log.Fatalf("Error loading golden file: %s", err)
	}
	googleService, err := google.NewAdminSrv(ctx, userEmail, serviceAccount, adminScope...)
	authingService := authing.NewAuthingService()
	if err != nil {
		log.L(ctx).Errorf("Error when calling `NewAdminServiceWithCre`: %s", err.Error())

		return
	}

	var AllGroups []*admin.Group
	err = googleService.Groups.List().Customer("my_customer").Query("name:G* email:g*").Pages(
		ctx, func(groups *admin.Groups) error {
			AllGroups = append(AllGroups, groups.Groups...)
			return nil
		})

	if err != nil {
		log.L(ctx).Errorf("Error when calling `googleService.Groups.List().Customer(\"my_customer\").Do()`: %s", err.Error())

		return
	}

	store, _ := mysql.GetMySQLFactoryOr(nil)
	for _, group := range AllGroups {
		if strings.HasPrefix(group.Name, DeptNamePre+"-") &&
			strings.HasPrefix(group.Email, Pre+"-") &&
			strings.HasPrefix(group.Description, Pre+":") {

			log.L(ctx).Debugf("group: %s", group.Name)

			authingId := strings.ReplaceAll(group.Description, Pre+":", "")
			department, err := authingService.GetDeptById(ctx, authingId)
			if err != nil {
				log.L(ctx).Errorf("Error when calling `authingService.GetDeptById(ctx, authingId)`: %s", err.Error())

				return

			}

			isDeleted, err := DeletedJudge(ctx, department, err, group, googleService)
			if err != nil || isDeleted {
				continue
			}

			if group.Name != "G-PingCAP" && department.Name != "PingCAP" { // not G-PingCAP
				var parentDept string
				dptNum := len(department.Path)
				if dptNum > 1 {
					pid := department.Path[dptNum-2]
					if pid == "6464b860b7da7062e8c97740" {
						parentDept = "PingCAP"
					} else {
						dptInDb, err := store.AuthingDepartment().GetDepartmentByAnyId(department.Path[dptNum-2])
						if err != nil {
							log.L(ctx).Errorf("Error when calling `store.Department().GetDepartmentByAnyId(department.Path[dptNum-1])`: %s", err.Error())

							continue
						}
						parentDept = dptInDb.Name
					}
					if parentDept == "Resilience Engineering" {
						fmt.Println("Resilience Engineering")
					}
				}

				tag := false

				mailInGoogle := getDeptMail(parentDept, department.Name)
				if mailInGoogle != group.Email {
					// group.Name = Delete + group.Name
					// err := UpdateGroup(ctx, googleService, group)
					err := DeleteGroup(ctx, googleService, group)

					if err != nil {
						return
					}
					tag = true
				}

				// compare name
				deptName := strings.TrimPrefix(group.Name, DeptNamePre+"-")
				if !tag && deptName != department.Name {
					// group.Name = Rename + group.Name
					// group.Email = DeleteEmail + group.Email
					// err := UpdateGroup(ctx, googleService, group)
					err := DeleteGroup(ctx, googleService, group)

					if err != nil {
						return
					}
				}
			}
			// find external user
			var AllMembers []*admin.Member
			err = googleService.Members.List(group.Email).Pages(
				ctx, func(members *admin.Members) error {
					AllMembers = append(AllMembers, members.Members...)
					return nil
				})
			if err != nil {
				log.L(ctx).Errorf("Error when calling `googleService.Members.List(group.Email).Do()`: %s", err.Error())
			}

			for _, member := range AllMembers {
				if member.Type == "EXTERNAL" || member.Status != "ACTIVE" {
					err := googleService.Members.Delete(group.Email, member.Email).Do()
					if err != nil {
						log.L(ctx).Errorf("Error when calling `googleService.Members.Delete(group.Email, member.Email).Do()`: %s", err.Error())

						return
					} else {
						log.L(ctx).Infof("Delete member success: %s %s", member.Email, group.Email)
					}
				}
			}
		}
	}

	log.L(ctx).Info("End to compare dept")
}
func DeletedJudge(ctx context.Context, department *authingmodel.OrgNodeChildStr,
	err error, group *admin.Group, googleService *admin.Service) (bool, error) {
	if err != nil {
		if strings.Contains(err.Error(), "not found") {
			err := DeleteGroup(ctx, googleService, group)
			if err != nil {
				return false, err
			}

			return true, nil
		} else {
			log.L(ctx).Errorf("Error when calling `authingService.GetDeptById(ctx, authingId)`: %s", err.Error())

			return false, err
		}
	} else if department == nil || (department.Id == "" &&
		department.Name == "" && department.OrgId == nil &&
		department.Code == nil) {
		// group.Name = Delete + group.Name
		// group.Email = DeleteEmail + group.Email
		// err := UpdateGroup(ctx, googleService, group)
		err := DeleteGroup(ctx, googleService, group)
		if err != nil {
			return false, err
		}

		return true, nil
	}
	return false, nil
}

func UpdateGroup(ctx context.Context, service *admin.Service, group *admin.Group) error {
	_, err := service.Groups.Update(group.Email, group).Do()
	if err != nil {
		log.L(ctx).Errorf("Error when calling `googleService.Groups.Update().Do()`: %s", err.Error())

		return err
	}
	log.L(ctx).Infof("Update group success: %s %s", group.Name, group.Email)

	return nil
}

func DeleteGroup(ctx context.Context, service *admin.Service, group *admin.Group) error {
	err := service.Groups.Delete(group.Email).Do()
	if err != nil {
		log.L(ctx).Errorf("Error when calling `googleService.Groups.Delete().Do()`: %s", err.Error())

		return err
	}
	log.L(ctx).Infof("Delete group success: %s %s", group.Name, group.Email)

	return nil
}
