package policy

import (
	"fmt"
	"net/http"
)

// template for error types
type baseError struct {
	className string
	msg       string
	code      int
}

// NamespaceValidationError is returned from ValidationNamespaces
type NamespaceValidationError baseError

func (n NamespaceValidationError) Error() string {
	return fmt.Sprintf("policy: %s", n.msg)
}

// GetClassName returns a class name for error checking client side
func (n NamespaceValidationError) GetClassName() string {
	if n.className != "" {
		return n.className
	}
	return "NamespaceValidationError"
}

// Code returns the HTTP status code that should be returned
func (n NamespaceValidationError) Code() int { return n.code }

var (
	// ErrMultipleEnvironments is returned when a user tries to create a role
	// with secrets from multiple environments.
	ErrMultipleEnvironments = NamespaceValidationError{
		className: "ErrMultipleEnvironments",
		msg:       "policy: policies can only contain keys from one environment",
		code:      http.StatusForbidden,
	}

	// ErrDisallowedWildcard is returned when a user tries to create a role
	// for a policy with wildcard in anything other than the secret name field.
	ErrDisallowedWildcard = NamespaceValidationError{
		className: "ErrDisallowedWildcard",
		msg:       "policy: wildcards only allowed in secret names",
		code:      http.StatusForbidden,
	}
)

// InvalidRolePolicyError handles the case that a role has >1 or <1 role policies
type InvalidRolePolicyError baseError

func (in InvalidRolePolicyError) Error() string {
	return fmt.Sprintf("Invalid RolePolicy: %s", in.msg)
}

// Code implements the apiserver.ApiErrorer interface,returning a http.StatusCode
func (in InvalidRolePolicyError) Code() int { return in.code }

// LegacyGroupDeletionFailure represents when a group can't be deleted
// because an owner can't be identified (no owner in pathPrefix)
type LegacyGroupDeletionFailure baseError

// Code to adhere to APIErrorer
func (le LegacyGroupDeletionFailure) Code() int { return le.code }

func (le LegacyGroupDeletionFailure) Error() string {
	return fmt.Sprintf("LegacyGroupDeletionFailure: %s", le.msg)
}

// InvalidRoleOwnerError represents an issue with roleOwners
type InvalidRoleOwnerError struct {
	msg  string
	code int
}

// Code implements the apiserver.ApiErrorer interface,returning a http.StatusCode
func (ir InvalidRoleOwnerError) Code() int { return ir.code }

func (ir InvalidRoleOwnerError) Error() string {
	return fmt.Sprintf("Invalid RoleOwner: %s", ir.msg)
}

var (
	// RoleOwnerAlreadyExists is used when trying to create
	// A roleOwner entry when the row already exists
	RoleOwnerAlreadyExists = InvalidRoleOwnerError{
		msg:  "roleOwner already exists",
		code: http.StatusConflict,
	}

	// RoleOwnerDoesNotExist is used when that occurs
	RoleOwnerDoesNotExist = InvalidRoleOwnerError{
		msg:  "roleOwner doesn't exist",
		code: http.StatusConflict,
	}

	// NoOwnersPassed is used when an owner is trying to be created without a slice of LDAPGroups
	NoOwnersPassed = InvalidRoleOwnerError{
		msg:  "No LDAPGroups passed for owners",
		code: http.StatusConflict,
	}

	// LegacyRoleWithoutRoleOwner is used when a non-admin user tries to set a roleOwner for a legacy role
	LegacyRoleWithoutRoleOwner = InvalidRoleOwnerError{
		msg:  "Can't pass roleOwners for legacy role",
		code: http.StatusConflict,
	}
)

// InvalidInputError represents invalid input pushed into a function
type InvalidInputError struct {
	prepend string //prepend with the name of the func error is occuring from
	msg     string //actual error msg
}

func (iie InvalidInputError) Error() string {
	if iie.prepend != "" {
		return fmt.Sprintf("%s:%s", iie.prepend, iie.msg)
	}
	return fmt.Sprintf("%s", iie.msg)

}

// Code returns an http status code for APIErrorer
func (iie InvalidInputError) Code() int { return 422 }
