package service

import (
	"errors"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	_ "github.com/go-sql-driver/mysql"
	"sync"
	"testData/global"
	Model "testData/model"
	"testData/request"
)

type CasbinService struct{}

var CasbinServiceApp = new(CasbinService)

func (ca *CasbinService) UpdateCasbin(roleId string, casbinInReceive *request.CasbinInReceive) error {
	var api []*Model.Api
	global.BaseDB.Where("api_group LIKE '%" + casbinInReceive.KeyWord +
		"%' OR description LIKE '%" + casbinInReceive.KeyWord + "%' OR path LIKE '%" + casbinInReceive.KeyWord + "%'").Find(&api)
	var casBin []*Model.Casbin
	var path []string
	for i := 0; i < len(api); i++ {
		path = append(path, api[i].Path)
	}
	global.BaseDB.Table("casbin_rule").Where("v0 = ? AND v1 NOT IN ?", roleId, path).Find(&casBin)
	var rules [][]string
	for i := 0; i < len(casBin); i++ {
		rules = append(rules, []string{casBin[i].AuthorityId, casBin[i].Path, casBin[i].Method, casBin[i].ApiId})
	}

	ok, err := ca.ClearCasbin(0, roleId)
	if err != nil {
		return errors.New("清理原api出错:" + err.Error())
	}
	for _, v := range casbinInReceive.CasbinInfos {
		cm := Model.Casbin{
			Ptype:       "p",
			AuthorityId: roleId,
			Path:        v.Path,
			Method:      v.Method,
		}
		rules = append(rules, []string{cm.AuthorityId, cm.Path, cm.Method, cm.ApiId})
	}
	e := ca.Casbin()
	ok, err = e.AddPolicies(rules)
	if !ok {
		return errors.New("添加失败,请联系管理员:" + err.Error())
	}
	return nil
}

func (ca *CasbinService) UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
	return global.BaseDB.Table("casbin_rule").Model(&Model.Casbin{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{
		"v1": newPath,
		"v2": newMethod,
	}).Error
}

func (ca *CasbinService) GetPolicyPathByAuthorityId(authorityId string) (pathMaps []request.CasbinInfo) {
	e := ca.Casbin()
	list := e.GetFilteredPolicy(0, authorityId)
	for _, v := range list {
		pathMaps = append(pathMaps, request.CasbinInfo{
			Path:   v[1],
			Method: v[2],
		})
	}
	return pathMaps
}

func (ca *CasbinService) ClearCasbin(v int, p ...string) (bool, error) {
	e := ca.Casbin()
	return e.RemoveFilteredPolicy(v, p...)

}

var (
	syncedEnforcer *casbin.SyncedEnforcer
	once           sync.Once
)

func (ca *CasbinService) Casbin() *casbin.SyncedEnforcer {
	once.Do(func() {
		a, _ := gormadapter.NewAdapterByDB(global.BaseDB)
		m, _ := model.NewModelFromString(`
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
`)
		syncedEnforcer, _ = casbin.NewSyncedEnforcer(m, a)
	})
	_ = syncedEnforcer.LoadPolicy()
	return syncedEnforcer
}
