package mysql

import (
	"context"
	"strings"

	"gorm.io/gorm"

	v1 "github.com/pingcap-inc/pchub/model/v1"
)

type department struct {
	db *gorm.DB
}

func newDepartment(ds *datastore) *department {
	return &department{db: ds.db}
}

func (dpt *department) List(ctx context.Context, pid, excludes string, precision int) ([]*v1.Department, error) {
	var res []*v1.Department

	d := dpt.db.
		Where("larkID <> '0' AND parentLarkID = ?", pid).
		Where("level <= ?", precision)

	if excludes != "" {
		exs := strings.Split(excludes, ",")
		d = d.Where("larkID NOT IN (?)", exs)
	}

	d = d.Order("name asc").Find(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (dpt *department) ListAll(ctx context.Context) (*v1.DepartmentList, error) {
	res := &v1.DepartmentList{}
	d := dpt.db.
		Order("id asc").
		Find(&res.Items)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (dpt *department) GetByLarkID(ctx context.Context, larkID string) (*v1.Department, error) {
	res := &v1.Department{}
	d := dpt.db.Where("larkID = ?", larkID).First(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (dpt *department) GetChainByLarkID(ctx context.Context, larkID string) (*[]v1.Department, error) {
	var res []v1.Department

	d := dpt.db.
		Where("larkID <> '0'").
		Where("larkID = ? OR FIND_IN_SET(?, flatChildrenLarkID)", larkID, larkID).
		Order("level asc").
		Find(&res)

	return &res, dbNotFoundErrorWrap(d.Error)
}

func (dpt *department) Sync(ctx context.Context, news, updates []*v1.Department, delIds []uint64) error {
	tx := dpt.db.Begin()

	// new
	if len(news) > 0 {
		err := tx.Create(news).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	// update
	for _, g := range updates {
		err := tx.Save(&g).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	// del
	err := tx.Where("id IN (?)", delIds).Delete(&v1.Department{}).Error
	if err != nil {
		tx.Rollback()

		return err
	}

	tx.Commit()

	return nil
}
