import { JsonPrimitive } from '@backstage/types';
import zodToJsonSchema from 'zod-to-json-schema';
import { Config } from '@backstage/config';

/**
 * The attributes related to a given permission; these should be generic and widely applicable to
 * all permissions in the system.
 * @public
 */
type PermissionAttributes = {
    action?: 'create' | 'read' | 'update' | 'delete';
};
/**
 * Generic type for building {@link Permission} types.
 * @public
 */
type PermissionBase<TType extends string, TFields extends object> = {
    /**
     * The name of the permission.
     */
    name: string;
    /**
     * {@link PermissionAttributes} which describe characteristics of the permission, to help
     * policy authors make consistent decisions for similar permissions without referring to them
     * all by name.
     */
    attributes: PermissionAttributes;
} & {
    /**
     * String value indicating the type of the permission (e.g. 'basic',
     * 'resource'). The allowed authorization flows in the permission system
     * depend on the type. For example, a `resourceRef` should only be provided
     * when authorizing permissions of type 'resource'.
     */
    type: TType;
} & TFields;
/**
 * A permission that can be checked through authorization.
 *
 * @remarks
 *
 * Permissions are the "what" part of authorization, the action to be performed. This may be reading
 * an entity from the catalog, executing a software template, or any other action a plugin author
 * may wish to protect.
 *
 * To evaluate authorization, a permission is paired with a Backstage identity (the "who") and
 * evaluated using an authorization policy.
 * @public
 */
type Permission = BasicPermission | ResourcePermission;
/**
 * A standard {@link Permission} with no additional capabilities or restrictions.
 * @public
 */
type BasicPermission = PermissionBase<'basic', {}>;
/**
 * ResourcePermissions are {@link Permission}s that can be authorized based on
 * characteristics of a resource such a catalog entity.
 * @public
 */
type ResourcePermission<TResourceType extends string = string> = PermissionBase<'resource', {
    /**
     * Denotes the type of the resource whose resourceRef should be passed when
     * authorizing.
     */
    resourceType: TResourceType;
}>;
/**
 * Options for authorization requests.
 * @public
 */
type AuthorizeRequestOptions = {
    token?: string;
};

/**
 * A request with a UUID identifier, so that batched responses can be matched up with the original
 * requests.
 * @public
 */
type IdentifiedPermissionMessage<T> = T & {
    id: string;
};
/**
 * A batch of request or response items.
 * @public
 */
type PermissionMessageBatch<T> = {
    items: IdentifiedPermissionMessage<T>[];
};
/**
 * The result of an authorization request.
 * @public
 */
declare const AuthorizeResult: {
    /**
     * The authorization request is denied.
     */
    readonly DENY: "DENY";
    /**
     * The authorization request is allowed.
     */
    readonly ALLOW: "ALLOW";
    /**
     * The authorization request is allowed if the provided conditions are met.
     */
    readonly CONDITIONAL: "CONDITIONAL";
};
/**
 * @public
 */
type AuthorizeResult = (typeof AuthorizeResult)[keyof typeof AuthorizeResult];
/**
 * @public
 */
declare namespace AuthorizeResult {
    type ALLOW = typeof AuthorizeResult.ALLOW;
    type DENY = typeof AuthorizeResult.DENY;
    type CONDITIONAL = typeof AuthorizeResult.CONDITIONAL;
}
/**
 * A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.
 *
 * @remarks
 *
 * This indicates that the policy unconditionally allows (or denies) the request.
 *
 * @public
 */
type DefinitivePolicyDecision = {
    result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;
};
/**
 * A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.
 *
 * @remarks
 *
 * This indicates that the policy allows authorization for the request, given that the returned
 * conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin
 * which knows about the referenced permission rules.
 *
 * @public
 */
type ConditionalPolicyDecision = {
    result: AuthorizeResult.CONDITIONAL;
    pluginId: string;
    resourceType: string;
    conditions: PermissionCriteria<PermissionCondition>;
};
/**
 * A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.
 *
 * @public
 */
type PolicyDecision = DefinitivePolicyDecision | ConditionalPolicyDecision;
/**
 * A condition returned with a CONDITIONAL authorization response.
 *
 * Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For
 * example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity
 * claims from a identity token.
 * @public
 */
type PermissionCondition<TResourceType extends string = string, TParams extends PermissionRuleParams = PermissionRuleParams> = {
    resourceType: TResourceType;
    rule: string;
    params?: TParams;
};
/**
 * Utility type to represent an array with 1 or more elements.
 * @ignore
 */
type NonEmptyArray<T> = [T, ...T[]];
/**
 * Represents a logical AND for the provided criteria.
 * @public
 */
type AllOfCriteria<TQuery> = {
    allOf: NonEmptyArray<PermissionCriteria<TQuery>>;
};
/**
 * Represents a logical OR for the provided criteria.
 * @public
 */
type AnyOfCriteria<TQuery> = {
    anyOf: NonEmptyArray<PermissionCriteria<TQuery>>;
};
/**
 * Represents a negation of the provided criteria.
 * @public
 */
type NotCriteria<TQuery> = {
    not: PermissionCriteria<TQuery>;
};
/**
 * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.
 * @public
 */
type PermissionCriteria<TQuery> = AllOfCriteria<TQuery> | AnyOfCriteria<TQuery> | NotCriteria<TQuery> | TQuery;
/**
 * A parameter to a permission rule.
 *
 * @public
 */
type PermissionRuleParam = undefined | JsonPrimitive | JsonPrimitive[];
/**
 * Types that can be used as parameters to permission rules.
 *
 * @public
 */
type PermissionRuleParams = undefined | Record<string, PermissionRuleParam>;
/**
 * An individual request sent to the permission backend.
 * @public
 */
type EvaluatePermissionRequest = {
    permission: Permission;
    resourceRef?: string;
};
/**
 * A batch of requests sent to the permission backend.
 * @public
 * @deprecated This type is not used and it will be removed in the future
 */
type EvaluatePermissionRequestBatch = PermissionMessageBatch<EvaluatePermissionRequest>;
/**
 * An individual response from the permission backend.
 *
 * @remarks
 *
 * This response type is an alias of {@link PolicyDecision} to maintain separation between the
 * {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend
 * api. They may diverge at some point in the future. The response
 *
 * @public
 */
type EvaluatePermissionResponse = PolicyDecision;
/**
 * A batch of responses from the permission backend.
 * @public
 */
type EvaluatePermissionResponseBatch = PermissionMessageBatch<EvaluatePermissionResponse>;
/**
 * Request object for {@link PermissionEvaluator.authorize}. If a {@link ResourcePermission}
 * is provided, it must include a corresponding `resourceRef`.
 * @public
 */
type AuthorizePermissionRequest = {
    permission: Exclude<Permission, ResourcePermission>;
    resourceRef?: never;
} | {
    permission: ResourcePermission;
    resourceRef: string;
};
/**
 * Response object for {@link PermissionEvaluator.authorize}.
 * @public
 */
type AuthorizePermissionResponse = DefinitivePolicyDecision;
/**
 * Request object for {@link PermissionEvaluator.authorizeConditional}.
 * @public
 */
type QueryPermissionRequest = {
    permission: ResourcePermission;
    resourceRef?: never;
};
/**
 * Response object for {@link PermissionEvaluator.authorizeConditional}.
 * @public
 */
type QueryPermissionResponse = PolicyDecision;
/**
 * A client interacting with the permission backend can implement this evaluator interface.
 *
 * @public
 */
interface PermissionEvaluator {
    /**
     * Evaluates {@link Permission | Permissions} and returns a definitive decision.
     */
    authorize(requests: AuthorizePermissionRequest[], options?: EvaluatorRequestOptions & {
        _ignored?: never;
    }): Promise<AuthorizePermissionResponse[]>;
    /**
     * Evaluates {@link ResourcePermission | ResourcePermissions} and returns both definitive and
     * conditional decisions, depending on the configured
     * {@link @backstage/plugin-permission-node#PermissionPolicy}. This method is useful when the
     * caller needs more control over the processing of conditional decisions. For example, a plugin
     * backend may want to use {@link PermissionCriteria | conditions} in a database query instead of
     * evaluating each resource in memory.
     */
    authorizeConditional(requests: QueryPermissionRequest[], options?: EvaluatorRequestOptions & {
        _ignored?: never;
    }): Promise<QueryPermissionResponse[]>;
}
/**
 * Options for {@link PermissionEvaluator} requests.
 *
 * This is currently empty, as there are no longer any common options for the permission evaluator.
 *
 * @public
 */
interface EvaluatorRequestOptions {
}

/**
 * This is a copy of the core DiscoveryApi, to avoid importing core.
 *
 * @public
 */
type DiscoveryApi = {
    getBaseUrl(pluginId: string): Promise<string>;
};

/**
 * Serialized permission rules, with the paramsSchema
 * converted from a ZodSchema to a JsonSchema.
 *
 * @public
 */
type MetadataResponseSerializedRule = {
    name: string;
    description: string;
    resourceType: string;
    paramsSchema?: ReturnType<typeof zodToJsonSchema>;
};
/**
 * Response type for the .metadata endpoint in
 * {@link @backstage/plugin-permission-node#createPermissionIntegrationRouter}
 *
 * @public
 */
type MetadataResponse = {
    permissions?: Permission[];
    rules: MetadataResponseSerializedRule[];
};

/**
 * A client interacting with the permission backend can implement this authorizer interface.
 * @public
 * @deprecated Use {@link @backstage/plugin-permission-common#PermissionEvaluator} instead
 */
interface PermissionAuthorizer {
    authorize(requests: EvaluatePermissionRequest[], options?: AuthorizeRequestOptions): Promise<EvaluatePermissionResponse[]>;
}

/**
 * Check if the two parameters are equivalent permissions.
 * @public
 */
declare function isPermission<T extends Permission>(permission: Permission, comparedPermission: T): permission is T;
/**
 * Check if a given permission is a {@link ResourcePermission}. When
 * `resourceType` is supplied as the second parameter, also checks if
 * the permission has the specified resource type.
 * @public
 */
declare function isResourcePermission<T extends string = string>(permission: Permission, resourceType?: T): permission is ResourcePermission<T>;
/**
 * Check if a given permission is related to a create action.
 * @public
 */
declare function isCreatePermission(permission: Permission): boolean;
/**
 * Check if a given permission is related to a read action.
 * @public
 */
declare function isReadPermission(permission: Permission): boolean;
/**
 * Check if a given permission is related to an update action.
 * @public
 */
declare function isUpdatePermission(permission: Permission): boolean;
/**
 * Check if a given permission is related to a delete action.
 * @public
 */
declare function isDeletePermission(permission: Permission): boolean;
/**
 * Convert {@link PermissionAuthorizer} to {@link PermissionEvaluator}.
 *
 * @public
 */
declare function toPermissionEvaluator(permissionAuthorizer: PermissionAuthorizer): PermissionEvaluator;

/**
 * Utility function for creating a valid {@link ResourcePermission}, inferring
 * the appropriate type and resource type parameter.
 *
 * @public
 */
declare function createPermission<TResourceType extends string>(input: {
    name: string;
    attributes: PermissionAttributes;
    resourceType: TResourceType;
}): ResourcePermission<TResourceType>;
/**
 * Utility function for creating a valid {@link BasicPermission}.
 *
 * @public
 */
declare function createPermission(input: {
    name: string;
    attributes: PermissionAttributes;
}): BasicPermission;

/**
 * Options for {@link PermissionClient} requests.
 *
 * @public
 */
type PermissionClientRequestOptions = {
    token?: string;
};
/**
 * An isomorphic client for requesting authorization for Backstage permissions.
 * @public
 */
declare class PermissionClient implements PermissionEvaluator {
    private readonly enabled;
    private readonly discovery;
    private readonly enableBatchedRequests;
    constructor(options: {
        discovery: DiscoveryApi;
        config: Config;
    });
    /**
     * {@inheritdoc PermissionEvaluator.authorize}
     */
    authorize(requests: AuthorizePermissionRequest[], options?: PermissionClientRequestOptions): Promise<AuthorizePermissionResponse[]>;
    /**
     * {@inheritdoc PermissionEvaluator.authorizeConditional}
     */
    authorizeConditional(queries: QueryPermissionRequest[], options?: PermissionClientRequestOptions): Promise<QueryPermissionResponse[]>;
    private makeRequest;
    private makeBatchedRequest;
    private makeRawRequest;
    private getAuthorizationHeader;
}

export { AuthorizeResult, PermissionClient, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator };
export type { AllOfCriteria, AnyOfCriteria, AuthorizePermissionRequest, AuthorizePermissionResponse, AuthorizeRequestOptions, BasicPermission, ConditionalPolicyDecision, DefinitivePolicyDecision, DiscoveryApi, EvaluatePermissionRequest, EvaluatePermissionRequestBatch, EvaluatePermissionResponse, EvaluatePermissionResponseBatch, EvaluatorRequestOptions, IdentifiedPermissionMessage, MetadataResponse, MetadataResponseSerializedRule, NotCriteria, Permission, PermissionAttributes, PermissionAuthorizer, PermissionBase, PermissionClientRequestOptions, PermissionCondition, PermissionCriteria, PermissionEvaluator, PermissionMessageBatch, PermissionRuleParam, PermissionRuleParams, PolicyDecision, QueryPermissionRequest, QueryPermissionResponse, ResourcePermission };
