package client

import (
	"fmt"

	apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
)

// wrapsErrType returns true if any error in the error tree of err is of type E.
func wrapsErrType[E error](err error) bool {
	switch e := err.(type) {
	case E:
		return true
	case interface{ Unwrap() error }:
		return wrapsErrType[E](e.Unwrap())
	case interface{ Unwrap() []error }:
		for _, ei := range e.Unwrap() {
			if wrapsErrType[E](ei) {
				return true
			}
		}
		return false
	default:
		return false
	}
}

// IsErrContainerNotFound checks if err corresponds to FrostFS status
// return corresponding to missing container. Supports wrapped errors.
func IsErrContainerNotFound(err error) bool {
	return wrapsErrType[*apistatus.ContainerNotFound](err)
}

// IsErrEACLNotFound checks if err corresponds to FrostFS status
// return corresponding to missing eACL table. Supports wrapped errors.
func IsErrEACLNotFound(err error) bool {
	return wrapsErrType[*apistatus.EACLNotFound](err)
}

// IsErrObjectNotFound checks if err corresponds to FrostFS status
// return corresponding to missing object. Supports wrapped errors.
func IsErrObjectNotFound(err error) bool {
	return wrapsErrType[*apistatus.ObjectNotFound](err)
}

// IsErrObjectAlreadyRemoved checks if err corresponds to FrostFS status
// return corresponding to already removed object. Supports wrapped errors.
func IsErrObjectAlreadyRemoved(err error) bool {
	return wrapsErrType[*apistatus.ObjectAlreadyRemoved](err)
}

// IsErrSessionExpired checks if err corresponds to FrostFS status return
// corresponding to expired session. Supports wrapped errors.
func IsErrSessionExpired(err error) bool {
	return wrapsErrType[*apistatus.SessionTokenExpired](err)
}

// IsErrSessionNotFound checks if err corresponds to FrostFS status return
// corresponding to missing session. Supports wrapped errors.
func IsErrSessionNotFound(err error) bool {
	return wrapsErrType[*apistatus.SessionTokenNotFound](err)
}

// returns error describing missing field with the given name.
func newErrMissingResponseField(name string) error {
	return fmt.Errorf("missing %s field in the response", name)
}

// returns error describing invalid field (according to the FrostFS protocol)
// with the given name and format violation err.
func newErrInvalidResponseField(name string, err error) error {
	return fmt.Errorf("invalid %s field in the response: %w", name, err)
}