package lark

import (
	"context"
	"time"

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

func SyncLarkDepartment(ctx context.Context) error {
	log.L(ctx).Info("sync lark department start")

	departmentsInLark, err := getDepartmentInLark(ctx)
	if err != nil {
		log.L(ctx).Errorf("Error when get departments in lark, err: %v", err)

		return err
	}

	mysqlStore, _ := mysql.GetMySQLFactoryOr(nil)
	departmentsInDb, err := mysqlStore.Department().ListAll(ctx)
	if err != nil {
		log.L(ctx).Errorf("Error when get departments in db, err: %v", err)

		return err
	}

	departInDbMap := make(map[string]model.LarkDepartment)
	dptVisMap := make(map[string]bool)
	for _, department := range departmentsInDb {
		departInDbMap[department.DepartmentID] = department
		dptVisMap[department.DepartmentID] = false
	}

	dptCreate, dptUpdate, dptDelete := diffDepartment(departmentsInLark, departInDbMap, dptVisMap)

	go func() {
		err = mysqlStore.Department().Sync(ctx, dptCreate, dptUpdate, dptDelete)
		if err != nil {
			log.L(ctx).Errorf("Error when sync departments, err: %v", err)

			return
		}
		log.L(ctx).Infof("Sync departments success")
	}()

	log.L(ctx).Info("sync lark department end")

	return nil
}

func getDepartmentInLark(ctx context.Context) ([]SubDepartment, error) {
	departments := make([]SubDepartment, 0)
	larkSrv := NewLarkService()
	pageToken := ""
	for {
		subDepartments, err := larkSrv.GetSubDepartment(ctx, "0", pageToken)
		if err != nil {
			log.L(ctx).Errorf("Error when get sub departments, err: %v", err)

			return nil, err
		}
		departments = append(departments, subDepartments.Items...)

		if !subDepartments.HasMore && subDepartments.PageToken == "" {
			break
		}
		pageToken = subDepartments.PageToken
	}
	return departments, nil

}

func diffDepartment(departmentInLark []SubDepartment, departInDbMap map[string]model.LarkDepartment, dptVisMap map[string]bool) (
	[]model.LarkDepartment, []model.LarkDepartment, []string) {

	dptCreate := make([]model.LarkDepartment, 0)
	dptUpdate := make([]model.LarkDepartment, 0)
	dptDelete := make([]string, 0)

	for _, depart := range departmentInLark {
		if depart.Status.IsDeleted {
			_, ok := departInDbMap[depart.DepartmentId]
			if ok {
				dptDelete = append(dptDelete, depart.DepartmentId)
			}
			continue
		}

		dptInDb, ok := departInDbMap[depart.DepartmentId]

		if ok {
			dpt, same := compareDepartment(depart, dptInDb)
			if same {
				dptUpdate = append(dptUpdate, dpt)
			}
			dptVisMap[depart.DepartmentId] = true
		} else {
			dpt := model.LarkDepartment{
				DepartmentID: depart.DepartmentId,
				Name:         depart.Name,
				ParentID:     depart.ParentDepartmentId,
				OpenId:       depart.OpenDepartmentId,
				LeaderUserId: depart.LeaderUserId,
				MemberCount:  depart.MemberCount,
				CreatedAt:    time.Now(),
			}
			dptCreate = append(dptCreate, dpt)
		}
	}

	for k, v := range dptVisMap {
		if !v {
			dptDelete = append(dptDelete, k)
		}
	}

	return dptCreate, dptUpdate, dptDelete
}

func compareDepartment(dptLark SubDepartment, dptDb model.LarkDepartment) (model.LarkDepartment, bool) {
	tmp := dptDb
	tag := false
	if dptLark.Name != dptDb.Name || dptLark.DepartmentId != dptDb.DepartmentID ||
		dptLark.OpenDepartmentId != dptDb.OpenId || dptLark.ParentDepartmentId != dptDb.ParentID ||
		dptLark.LeaderUserId != dptDb.LeaderUserId || dptLark.MemberCount != dptDb.MemberCount {
		tag = true
	}
	if tag {
		tmp.DepartmentID = dptLark.DepartmentId
		tmp.ParentID = dptLark.ParentDepartmentId
		tmp.Name = dptLark.Name
		tmp.MemberCount = dptLark.MemberCount
		tmp.LeaderUserId = dptLark.LeaderUserId
		tmp.OpenId = dptLark.OpenDepartmentId
	}
	return tmp, tag
}
