package adminroles

import (
	"strings"

	"github.com/fiskerinc/cloud-services/pkg/validator"

	"github.com/pkg/errors"
)

const MissingPermissionError = "missing permission"

type RolesChecker struct {
	RequiredRoles []string
}

func (rc *RolesChecker) Check(roles []string) error {
	if len(rc.RequiredRoles) != 0 {
		return rc.HasRole(roles)
	}

	return nil
}

func (rc *RolesChecker) CheckGroups(groups interface{}) error {
	if len(rc.RequiredRoles) != 0 {
		roles, err := rc.parseRolesFromGroups(groups)
		if err != nil {
			return errors.New(MissingPermissionError)
		}

		return rc.HasRole(roles)
	}

	return nil
}

func (rc *RolesChecker) HasRole(roles []string) error {
	err := validator.ValidateField(roles, "max=1024,dive,uuid")
	if err != nil {
		return errors.WithStack(err)
	}

	for _, required := range rc.RequiredRoles {
		if rc.containsRole(required, roles) {
			return nil
		}
	}

	return errors.New(MissingPermissionError)
}

func (rc *RolesChecker) parseRolesFromGroups(groups interface{}) ([]string, error) {

	if str, ok := groups.(string); ok {
		return rc.parseStringRoles(str)
	}

	if items, ok := groups.([]interface{}); ok && len(items) > 0 {
		if _, ok := items[0].(string); ok {
			return rc.parseSliceRoles(items)
		}
	}
	return nil, errors.New(MissingPermissionError)
}

func (rc *RolesChecker) parseSliceRoles(groups []interface{}) ([]string, error) {
	items := make([]string, len(groups))

	for i, item := range groups {
		items[i] = item.(string)
	}

	return items, nil
}

func (rc *RolesChecker) parseStringRoles(groups string) ([]string, error) {
	clean := strings.Trim(strings.ReplaceAll(groups, " ", ""), "[]")
	if len(clean) == 0 {
		return nil, errors.New(MissingPermissionError)
	}

	items := strings.Split(clean, ",")
	if items == nil || len(items) == 0 {
		return nil, errors.New(MissingPermissionError)
	}

	return items, nil
}

func (rc *RolesChecker) containsRole(role string, groups []string) bool {
	for _, group := range groups {
		if role == group {
			return true
		}
	}

	return false
}

func (rc *RolesChecker) SetRequiredRoles(roles []RoleID) {
	result := make([]string, len(roles))

	for i, role := range roles {
		result[i] = string(role)
	}

	rc.RequiredRoles = result
}
