package mysql

import (
	"context"

	"gorm.io/gorm"

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

type resourceMemberAccess struct {
	db *gorm.DB
}

func newResourceMemberAccess(ds *datastore) *resourceMemberAccess {
	return &resourceMemberAccess{db: ds.db}
}

func (u *resourceMemberAccess) Create(_ context.Context, member *v1.ResourceMemberAccess) (*v1.ResourceMemberAccess, error) {
	return member, u.db.Create(member).Error
}

func (u *resourceMemberAccess) Update(_ context.Context, member *v1.ResourceMemberAccess) error {
	return u.db.Save(member).Error
}

func (u *resourceMemberAccess) Delete(_ context.Context, member *v1.ResourceMemberAccess) error {
	return u.db.Delete(member).Error
}

func (u *resourceMemberAccess) Get(_ context.Context, member *v1.ResourceMemberAccess) (v1.ResourceMemberAccess, error) {
	memberInDb := v1.ResourceMemberAccess{}
	err := u.db.Where(member).First(&memberInDb).Error

	return memberInDb, err
}

func (u *resourceMemberAccess) ListByLarkID(ctx context.Context, luid string) ([]*v1.ResourceMemberAccess, error) {
	var res []*v1.ResourceMemberAccess
	d := u.db.
		Model(&v1.ResourceMemberAccess{}).
		Where("memberLarkID = ?", luid).
		Find(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (u *resourceMemberAccess) DeleteByIDs(ctx context.Context, ids []uint64) error {
	return u.db.Model(&v1.ResourceMemberAccess{}).Delete(&v1.ResourceMemberAccess{}, ids).Error
}

func (u *resourceMemberAccess) ListByResourceID(ctx context.Context, rid uint64) ([]*v1.ResourceMemberAccess, error) {
	var res []*v1.ResourceMemberAccess
	d := u.db.
		Model(&v1.ResourceMemberAccess{}).
		Joins("Member").
		Joins("Role").
		Where("resourceID = ?", rid)
	// if provider == "GCP" {
	// 	d.Where("Role.code like ?", "basic%")
	// }
	d = d.Find(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (u *resourceMemberAccess) ListByResourceIDs(ctx context.Context, rid []uint64) ([]*v1.ResourceMemberAccess, error) {
	var res []*v1.ResourceMemberAccess
	d := u.db.
		Model(&v1.ResourceMemberAccess{}).
		Joins("Member").
		Joins("Role").
		Where("resourceID IN (?)", rid)
	// if provider == "GCP" {
	// 	d.Where("Role.code like ?", "basic%")
	// }
	d = d.Find(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}

func (u *resourceMemberAccess) SyncToDB(ctx context.Context, add, del []v1.ResourceMemberAccess) error {
	tx := u.db.Begin()

	if len(add) > 0 {
		err := tx.Create(&add).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	delIDs := make([]uint64, 0)
	for _, d := range del {
		delIDs = append(delIDs, d.ID)
	}
	if len(delIDs) > 0 {
		err := tx.Save(del).Error
		if err != nil {
			tx.Rollback()

			return err
		}
		err = tx.Delete(&v1.ResourceMemberAccess{}, delIDs).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}
	tx.Commit()

	return nil
}

func (u *resourceMemberAccess) ListByRIDs(ctx context.Context, rIDs []uint64) ([]v1.ResourceMemberAccess, error) {
	var res []v1.ResourceMemberAccess
	d := u.db.
		Model(&v1.ResourceMemberAccess{}).
		Where("roleID in (?)", rIDs).
		Find(&res)

	return res, dbNotFoundErrorWrap(d.Error)
}
