package errors

import (
	"fmt"
	"net/http"

	"code.justin.tv/systems/guardian/guardian"
)

// ForbiddenError is returned when attempting to create a policy containing
// keys and/or namespaces the user does not have access to view.
type ForbiddenError struct {
	Keys []string       `json:"keys"`
	User *guardian.User `json:"user"`
}

func (fe ForbiddenError) String() string { return fe.Error() }

func (fe ForbiddenError) Error() string {
	return fmt.Sprintf("User %s does not have access to keys %s. User's groups: %v", fe.User.CN, fe.Keys, fe.User.Groups)
}

// Code allows for adherence to APIErrorer
func (fe ForbiddenError) Code() int { return http.StatusForbidden }

// AddKeys is a helper to add key to Keys slice
func (fe *ForbiddenError) AddKeys(keys []string) {
	fe.Keys = append(fe.Keys, keys...)
}

// IsForbiddenError checks to see if error is of type ForbiddenError
func IsForbiddenError(err error) bool {
	if _, ok := err.(*ForbiddenError); ok {
		return true
	}
	return false
}

// ForbiddenNamespace is returned when a user doesn't have access to a particular namespace
type ForbiddenNamespace struct {
	Namespace string
	User      *guardian.User
}

func (fn ForbiddenNamespace) Error() string {
	return fmt.Sprintf("User %s does not have access to namespace %s. User's groups: %v", fn.User.CN, fn.Namespace, fn.User.Groups)
}

// Code allows for adherence to APIErrorer
func (fn ForbiddenNamespace) Code() int { return http.StatusForbidden }

//InvalidRequestError represents a malformed request
type InvalidRequestError struct {
	Message error
}

// Error returns the error string
func (ire InvalidRequestError) Error() string {
	return ire.Message.Error()
}

// Code is the status code associated with the error
func (ire InvalidRequestError) Code() int { return 422 } //Unprocessable Entity

// InvalidLDAPGroupsError is returned when a user's ldap groups
// aren't allowed to access the resource
type InvalidLDAPGroupsError struct {
	User   *guardian.User
	Groups []string
}

// Error returns the error string
func (ilg InvalidLDAPGroupsError) Error() string {
	return fmt.Sprintf("User %s is not a member of an administrative group. User's groups: %s, Owner groups %s", ilg.User.CN, ilg.User.Groups, ilg.Groups)
}

// Code is the status code associated with the error
func (ilg InvalidLDAPGroupsError) Code() int { return http.StatusForbidden }

// SecretTombstonedError will be returned if Tombstone is set to true when
// trying to unmarshall a secret
type SecretTombstonedError struct {
}

func (err SecretTombstonedError) Error() string {
	return fmt.Sprintf("Secret has been tombstoned")
}

// IsSecretTombstoned checks if an error is SecretTombstonedError
func IsSecretTombstoned(err error) bool {
	if _, ok := err.(SecretTombstonedError); ok {
		return true
	}
	return false
}
