import { Entity, CompoundEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
import { LoggerService, UrlReaderService, DiscoveryService } from '@backstage/backend-plugin-api';
import express from 'express';
import { StorageOptions } from '@google-cloud/storage';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { IndexableDocument } from '@backstage/plugin-search-common';
import { Writable } from 'node:stream';
import * as winston from 'winston';
import { Logger } from 'winston';

/**
 * A unique identifier of the tree blob, usually the commit SHA or etag from the target.
 * @public
 */
type ETag = string;
/**
 * Options for building preparers
 * @public
 */
type PreparerConfig = {
    logger: LoggerService;
    reader: UrlReaderService;
};
/**
 * Options for configuring the content preparation process.
 * @public
 */
type PreparerOptions = {
    /**
     * An instance of the logger
     */
    logger?: LoggerService;
    /**
     * see {@link ETag}
     */
    etag?: ETag;
};
/**
 * Result of the preparation step.
 * @public
 */
type PreparerResponse = {
    /**
     * The path to directory where the tree is downloaded.
     */
    preparedDir: string;
    /**
     * see {@link ETag}
     */
    etag: ETag;
};
/**
 * Definition of a TechDocs preparer
 * @public
 */
type PreparerBase = {
    /**
     * Given an Entity definition from the Software Catalog, go and prepare a directory
     * with contents from the location in temporary storage and return the path.
     *
     * @param entity - The entity from the Software Catalog
     * @param options - If etag is provided, it will be used to check if the target has
     *        updated since the last build.
     * @throws `NotModifiedError` when the prepared directory has not been changed since the last build.
     */
    prepare(entity: Entity, options?: PreparerOptions): Promise<PreparerResponse>;
    /**
     * Indicates whether the prepared directory should be cleaned after generation.
     */
    shouldCleanPreparedDirectory(): boolean;
};
/**
 * Definition for a TechDocs preparer builder
 * @public
 */
type PreparerBuilder = {
    register(protocol: RemoteProtocol, preparer: PreparerBase): void;
    get(entity: Entity): PreparerBase;
};
/**
 * Location where documentation files are stored
 * @public
 */
type RemoteProtocol = 'url' | 'dir';

/**
 * Parsed location annotation
 * @public
 */
type ParsedLocationAnnotation = {
    type: RemoteProtocol;
    target: string;
};
/**
 * Returns a parsed locations annotation
 * @public
 * @param annotationName - The name of the annotation in the entity metadata
 * @param entity - A TechDocs entity instance
 */
declare const parseReferenceAnnotation: (annotationName: string, entity: Entity) => ParsedLocationAnnotation;
/**
 * TechDocs references of type `dir` are relative the source location of the entity.
 * This function transforms relative references to absolute ones, based on the
 * location the entity was ingested from. If the entity was registered by a `url`
 * location, it returns a `url` location with a resolved target that points to the
 * targeted subfolder. If the entity was registered by a `file` location, it returns
 * an absolute `dir` location.
 * @public
 * @param entity - the entity with annotations
 * @param dirAnnotation - the parsed techdocs-ref annotation of type 'dir'
 * @param scmIntegrations - access to the scmIntegration to do url transformations
 * @throws if the entity doesn't specify a `dir` location or is ingested from an unsupported location.
 * @returns the transformed location with an absolute target.
 */
declare const transformDirLocation: (entity: Entity, dirAnnotation: ParsedLocationAnnotation, scmIntegrations: ScmIntegrationRegistry) => {
    type: "dir" | "url";
    target: string;
};
/**
 * Returns an entity reference based on the TechDocs annotation type
 * @public
 * @param entity - A TechDocs instance
 * @param scmIntegration - An implementation for  SCM integration API
 */
declare const getLocationForEntity: (entity: Entity, scmIntegration: ScmIntegrationRegistry) => ParsedLocationAnnotation;
/**
 * Returns a preparer response {@link PreparerResponse}
 * @public
 * @param reader - Read a tree of files from a repository
 * @param entity - A TechDocs entity instance
 * @param opts - Options for configuring the reader, e.g. logger, etag, etc.
 */
declare const getDocFilesFromRepository: (reader: UrlReaderService, entity: Entity, opts?: {
    etag?: string;
    logger?: LoggerService;
}) => Promise<PreparerResponse>;

/**
 * Options for building generators
 * @public
 */
type GeneratorOptions = {
    logger: LoggerService;
    containerRunner?: TechDocsContainerRunner;
};
/**
 * The values that the generator will receive.
 *
 * @public
 * @param inputDir - The directory of the uncompiled documentation, with the values from the frontend
 * @param outputDir - Directory to store generated docs in. Usually - a newly created temporary directory.
 * @param parsedLocationAnnotation - backstage.io/techdocs-ref annotation of an entity
 * @param etag - A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json.
 * @param logger - A logger that forwards the messages to the caller to be displayed outside of the backend.
 * @param logStream - A log stream that can send raw log messages to the caller to be displayed outside of the backend.
 * @param siteOptions - Options for the site: The `name` property will be used in mkdocs.yml config for the required `site_name` property, default value is "Documentation Site"
 */
type GeneratorRunOptions = {
    inputDir: string;
    outputDir: string;
    parsedLocationAnnotation?: ParsedLocationAnnotation;
    etag?: string;
    logger: Logger;
    logStream?: Writable;
    siteOptions?: {
        name?: string;
    };
    runAsDefaultUser?: boolean;
};
/**
 * Generates documentation files
 * @public
 */
type GeneratorBase = {
    /**
     * Runs the generator with the values
     * @public
     */
    run(opts: GeneratorRunOptions): Promise<void>;
};
/**
 * List of supported generator options
 * @public
 */
type SupportedGeneratorKey = 'techdocs' | string;
/**
 * The generator builder holds the generator ready for run time
 * @public
 */
type GeneratorBuilder = {
    register(protocol: SupportedGeneratorKey, generator: GeneratorBase): void;
    get(entity: Entity): GeneratorBase;
};
/**
 * Handles the running of containers to generate TechDocs.
 *
 * Custom implementations, e.g. for Kubernetes or other execution environments, can be inspired by the internal default
 * implementation `DockerContainerRunner`.
 *
 * @public
 */
interface TechDocsContainerRunner {
    /**
     * Runs a container image to completion.
     */
    runContainer(opts: {
        imageName: string;
        command?: string | string[];
        args: string[];
        logStream?: Writable;
        mountDirs?: Record<string, string>;
        workingDir?: string;
        envVars?: Record<string, string>;
        pullImage?: boolean;
        defaultUser?: boolean;
        pullOptions?: {
            authconfig?: {
                username?: string;
                password?: string;
                auth?: string;
                email?: string;
                serveraddress?: string;
                [key: string]: unknown;
            };
            [key: string]: unknown;
        };
    }): Promise<void>;
}

/**
 * Generates documentation files
 * @public
 */
declare class TechdocsGenerator implements GeneratorBase {
    /**
     * The default docker image (and version) used to generate content. Public
     * and static so that techdocs-node consumers can use the same version.
     *
     * See {@link https://hub.docker.com/r/spotify/techdocs/tags} for list of available versions.
     */
    static readonly defaultDockerImage = "spotify/techdocs:v1.2.8";
    private readonly logger;
    private readonly containerRunner?;
    private readonly options;
    private readonly scmIntegrations;
    /**
     * Returns a instance of TechDocs generator
     * @param config - A Backstage configuration
     * @param options - Options to configure the generator
     */
    static fromConfig(config: Config, options: GeneratorOptions): TechdocsGenerator;
    constructor(options: {
        logger: LoggerService;
        containerRunner?: TechDocsContainerRunner;
        config: Config;
        scmIntegrations: ScmIntegrationRegistry;
    });
    /** {@inheritDoc GeneratorBase.run} */
    run(options: GeneratorRunOptions): Promise<void>;
}

/**
 * Collection of docs generators
 * @public
 */
declare class Generators implements GeneratorBuilder {
    private generatorMap;
    /**
     * Returns a generators instance containing a generator for TechDocs
     * @param config - A Backstage configuration
     * @param options - Options to configure the TechDocs generator
     */
    static fromConfig(config: Config, options: {
        logger: LoggerService;
        containerRunner?: TechDocsContainerRunner;
        customGenerator?: TechdocsGenerator;
    }): Promise<GeneratorBuilder>;
    /**
     * Register a generator in the generators collection
     * @param generatorKey - Unique identifier for the generator
     * @param generator - The generator instance to register
     */
    register(generatorKey: SupportedGeneratorKey, generator: GeneratorBase): void;
    /**
     * Returns the generator for a given TechDocs entity
     * @param entity - A TechDocs entity instance
     */
    get(entity: Entity): GeneratorBase;
}

/**
 * Finds and loads the contents of an mkdocs.yml, mkdocs.yaml file, a file
 * with a specified name or an ad-hoc created file with minimal config.
 * @public
 *
 * @param inputDir - base dir to be searched for either an mkdocs.yml or mkdocs.yaml file.
 * @param options - name: default mkdocs site_name to be used with a ad hoc file default value is "Documentation Site"
 *                  mkdocsConfigFileName (optional): a non-default file name to be used as the config
 */
declare const getMkdocsYml: (inputDir: string, options?: {
    name?: string;
    mkdocsConfigFileName?: string;
}) => Promise<{
    path: string;
    content: string;
    configIsTemporary: boolean;
}>;

/**
 * @public
 * @deprecated
 * Deprecated in favor of getMkdocsYml (lowercase 'd')
 */
declare const getMkDocsYml: (inputDir: string, options?: {
    name?: string;
    mkdocsConfigFileName?: string;
}) => Promise<{
    path: string;
    content: string;
    configIsTemporary: boolean;
}>;

/**
 * Preparer used to retrieve documentation files from a local directory
 * @public
 */
declare class DirectoryPreparer implements PreparerBase {
    private readonly scmIntegrations;
    private readonly reader;
    /**
     * Returns a directory preparer instance
     * @param config - A backstage config
     * @param options - A directory preparer options containing a logger and reader
     */
    static fromConfig(config: Config, options: PreparerConfig): DirectoryPreparer;
    private constructor();
    /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */
    shouldCleanPreparedDirectory(): boolean;
    /** {@inheritDoc PreparerBase.prepare} */
    prepare(entity: Entity, options?: PreparerOptions): Promise<PreparerResponse>;
}

/**
 * Preparer used to retrieve documentation files from a remote repository
 * @public
 */
declare class UrlPreparer implements PreparerBase {
    private readonly logger;
    private readonly reader;
    /**
     * Returns a directory preparer instance
     * @param config - A URL preparer config containing the a logger and reader
     */
    static fromConfig(options: PreparerConfig): UrlPreparer;
    private constructor();
    /** {@inheritDoc PreparerBase.shouldCleanPreparedDirectory} */
    shouldCleanPreparedDirectory(): boolean;
    /** {@inheritDoc PreparerBase.prepare} */
    prepare(entity: Entity, options?: PreparerOptions): Promise<PreparerResponse>;
}

/**
 * Collection of docs preparers (dir and url)
 * @public
 */
declare class Preparers implements PreparerBuilder {
    private preparerMap;
    /**
     * Returns a generators instance containing a generator for TechDocs
     * @public
     * @param backstageConfig - A Backstage configuration
     * @param preparerConfig - Options to configure preparers
     */
    static fromConfig(backstageConfig: Config, options: PreparerConfig): Promise<PreparerBuilder>;
    /**
     * Register a preparer in the preparers collection
     * @param protocol - url or dir to associate with preparer
     * @param preparer - The preparer instance to set
     */
    register(protocol: RemoteProtocol, preparer: PreparerBase): void;
    /**
     * Returns the preparer for a given TechDocs entity
     * @param entity - A TechDocs entity instance
     * @returns
     */
    get(entity: Entity): PreparerBase;
}

/**
 * Options for building publishers
 * @public
 */
type PublisherFactory = {
    logger: LoggerService;
    discovery: DiscoveryService;
    customPublisher?: PublisherBase | undefined;
    publisherSettings?: PublisherSettings;
};
/**
 * Additional configurations for publishers.
 * @public
 */
interface PublisherSettings {
    googleGcs?: StorageOptions;
}
/**
 * Key for all the different types of TechDocs publishers that are supported.
 * @public
 */
type PublisherType = 'local' | 'googleGcs' | 'awsS3' | 'azureBlobStorage' | 'openStackSwift';
/**
 * Request publish definition
 * @public
 */
type PublishRequest = {
    entity: Entity;
    directory: string;
};
/**
 * Response containing metadata about where files were published and what may
 * have been published or updated.
 * @public
 */
type PublishResponse = {
    /**
     * The URL which serves files from the local publisher's static directory.
     */
    remoteUrl?: string;
    /**
     * The list of objects (specifically their paths) that were published.
     * Objects do not have a preceding slash, and match how one would load the
     * object over the `/static/docs/*` TechDocs Backend Plugin endpoint.
     */
    objects?: string[];
} | void;
/**
 * Result for the validation check.
 * @public
 */
type ReadinessResponse = {
    /** If true, the publisher is able to interact with the backing storage. */
    isAvailable: boolean;
};
/**
 * Type to hold metadata found in techdocs_metadata.json and associated with each site
 * @param etag - ETag of the resource used to generate the site. Usually the latest commit sha of the source repository.
 * @public
 */
type TechDocsMetadata = {
    site_name: string;
    site_description: string;
    etag: string;
    build_timestamp: number;
    files?: string[];
};
/**
 * TechDocs entity triplet migration request
 * @public
 */
type MigrateRequest = {
    /**
     * Whether or not to remove the source file. Defaults to false (acting like a
     * copy instead of a move).
     */
    removeOriginal?: boolean;
    /**
     * Maximum number of files/objects to migrate at once. Defaults to 25.
     */
    concurrency?: number;
};
/**
 * Base class for a TechDocs publisher (e.g. Local, Google GCS Bucket, AWS S3, etc.)
 * The publisher handles publishing of the generated static files after the prepare and generate steps of TechDocs.
 * It also provides APIs to communicate with the storage service.
 *
 * @public
 */
interface PublisherBase {
    /**
     * Check if the publisher is ready. This check tries to perform certain checks to see if the
     * publisher is configured correctly and can be used to publish or read documentations.
     * The different implementations might e.g. use the provided service credentials to access the
     * target or check if a folder/bucket is available.
     */
    getReadiness(): Promise<ReadinessResponse>;
    /**
     * Store the generated static files onto a storage service (either local filesystem or external service).
     *
     * @param request - Object containing the entity from the service
     *                  catalog, and the directory that contains the generated static files from TechDocs.
     */
    publish(request: PublishRequest): Promise<PublishResponse>;
    /**
     * Retrieve TechDocs Metadata about a site e.g. name, contributors, last updated, etc.
     * This API uses the techdocs_metadata.json file that co-exists along with the generated docs.
     */
    fetchTechDocsMetadata(entityName: CompoundEntityRef): Promise<TechDocsMetadata>;
    /**
     * Route middleware to serve static documentation files for an entity.
     */
    docsRouter(): express.Handler;
    /**
     * Check if the index.html is present for the Entity at the Storage location.
     */
    hasDocsBeenGenerated(entityName: Entity): Promise<boolean>;
    /**
     * Migrates documentation objects with case sensitive entity triplets to
     * lowercase entity triplets. This was (will be) a change introduced in
     * `techdocs-cli` version `{0.x.y}` and `techdocs-backend` version `{0.x.y}`.
     *
     * Implementation of this method is unnecessary in publishers introduced
     * after version `{0.x.y}` of `techdocs-node`.
     */
    migrateDocsCase?(migrateRequest: MigrateRequest): Promise<void>;
}
/**
 * Definition for a TechDocs publisher builder
 * @public
 */
type PublisherBuilder = {
    register(type: PublisherType, publisher: PublisherBase): void;
    get(config: Config): PublisherBase;
};

/**
 * Factory class to create a TechDocs publisher based on defined publisher type in app config.
 * Uses `techdocs.publisher.type`.
 * @public
 */
declare class Publisher implements PublisherBuilder {
    private publishers;
    register(type: PublisherType | 'techdocs', publisher: PublisherBase): void;
    get(config: Config): PublisherBase;
    /**
     * Returns a instance of TechDocs publisher
     * @param config - A Backstage configuration
     * @param options - Options for configuring the publisher factory
     */
    static fromConfig(config: Config, options: PublisherFactory): Promise<PublisherBase>;
}

/**
 * TechDocs indexable document interface
 * @public
 */
interface TechDocsDocument extends IndexableDocument {
    /**
     * Entity kind
     */
    kind: string;
    /**
     * Entity metadata namespace
     */
    namespace: string;
    /**
     * Entity metadata name
     */
    name: string;
    /**
     * Entity lifecycle
     */
    lifecycle: string;
    /**
     * Entity owner
     */
    owner: string;
    /**
     * Entity path
     */
    path: string;
}
/**
 * A strategy for when to build TechDocs locally, and when to skip building TechDocs (allowing for an external build)
 *
 * @public
 */
interface DocsBuildStrategy {
    shouldBuild(params: {
        entity: Entity;
    }): Promise<boolean>;
}

/**
 * Extension point type for configuring TechDocs builds.
 *
 * @public
 */
interface TechdocsBuildsExtensionPoint {
    setBuildStrategy(buildStrategy: DocsBuildStrategy): void;
    setBuildLogTransport(transport: winston.transport): void;
}
/**
 * Extension point for configuring TechDocs builds.
 *
 * @public
 */
declare const techdocsBuildsExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint<TechdocsBuildsExtensionPoint>;
/**
 * Extension point type for configuring a custom TechDocs generator
 *
 * @public
 */
interface TechdocsGeneratorExtensionPoint {
    setTechdocsGenerator(generator: TechdocsGenerator): void;
}
/**
 * Extension point for configuring a custom TechDocs generator
 *
 * @public
 */
declare const techdocsGeneratorExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint<TechdocsGeneratorExtensionPoint>;
/**
 * Extension point type for configuring a custom TechDocs preparer
 *
 * @public
 */
interface TechdocsPreparerExtensionPoint {
    registerPreparer(protocol: RemoteProtocol, preparer: PreparerBase): void;
}
/**
 * Extension point for configuring a custom TechDocs preparer
 *
 * @public
 */
declare const techdocsPreparerExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint<TechdocsPreparerExtensionPoint>;
/**
 * Extension point type for configuring a custom TechDocs publisher
 *
 * @public
 */
interface TechdocsPublisherExtensionPoint {
    registerPublisher(type: PublisherType, publisher: PublisherBase): void;
    registerPublisherSettings<T extends keyof PublisherSettings>(publisher: T, settings: PublisherSettings[T]): void;
}
/**
 * Extension point for configuring a custom TechDocs publisher
 *
 * @public
 */
declare const techdocsPublisherExtensionPoint: _backstage_backend_plugin_api.ExtensionPoint<TechdocsPublisherExtensionPoint>;

export { DirectoryPreparer, Generators, Preparers, Publisher, TechdocsGenerator, UrlPreparer, getDocFilesFromRepository, getLocationForEntity, getMkDocsYml, getMkdocsYml, parseReferenceAnnotation, techdocsBuildsExtensionPoint, techdocsGeneratorExtensionPoint, techdocsPreparerExtensionPoint, techdocsPublisherExtensionPoint, transformDirLocation };
export type { DocsBuildStrategy, ETag, GeneratorBase, GeneratorBuilder, GeneratorOptions, GeneratorRunOptions, MigrateRequest, ParsedLocationAnnotation, PreparerBase, PreparerBuilder, PreparerConfig, PreparerOptions, PreparerResponse, PublishRequest, PublishResponse, PublisherBase, PublisherBuilder, PublisherFactory, PublisherSettings, PublisherType, ReadinessResponse, RemoteProtocol, SupportedGeneratorKey, TechDocsContainerRunner, TechDocsDocument, TechDocsMetadata, TechdocsBuildsExtensionPoint, TechdocsGeneratorExtensionPoint, TechdocsPreparerExtensionPoint, TechdocsPublisherExtensionPoint };
