import { WorkerLogLevel, WorkerOutput } from "@webda/workout";
import { JSONSchema7 } from "json-schema";
import { OpenAPIV3 } from "openapi-types";
import { Constructor, Core, CoreModel, CoreModelDefinition, Service } from "./index.js";
export type PackageDescriptorAuthor = string | {
    name?: string;
    email?: string;
    url?: string;
};
export type Modda = ServiceConstructor<Service>;
/**
 * Defined relationship for one model
 */
export type ModelGraph = {
    parent?: Omit<ModelRelation, "type">;
    links?: ModelRelation[];
    queries?: {
        attribute: string;
        model: string;
        targetAttribute: string;
    }[];
    maps?: {
        attribute: string;
        model: string;
        targetAttributes: string[];
        targetLink: string;
        cascadeDelete: boolean;
    }[];
    children?: string[];
    binaries?: {
        attribute: string;
        cardinality: "ONE" | "MANY";
        metadata?: string;
    }[];
};
/**
 * Defined relationship for all models
 */
export type ModelsGraph = {
    [key: string]: ModelGraph;
};
/**
 * Some package exists but seems pretty big for this
 * https://classic.yarnpkg.com/en/docs/package-json
 */
export interface PackageDescriptor {
    name?: string;
    version?: string;
    description?: string;
    keywords?: string[];
    license?: string | {
        name: string;
    };
    homepage?: string;
    bugs?: string;
    repository?: string;
    author?: PackageDescriptorAuthor;
    contributors?: string[] | PackageDescriptorAuthor[];
    files?: string[];
    main?: string;
    bin?: string | {
        [key: string]: string;
    };
    man?: string | string[];
    directories?: {
        [key: string]: string;
    };
    scripts?: {
        [key: string]: string;
    };
    config?: any;
    dependencies?: {
        [key: string]: string;
    };
    devDependencies?: {
        [key: string]: string;
    };
    peerDependencies?: {
        [key: string]: string;
    };
    peerDependenciesMeta?: {
        [key: string]: {
            optional: boolean;
        };
    };
    optionalDependencies?: {
        [key: string]: string;
    };
    bundledDependencies?: string[];
    flat?: boolean;
    resolutions?: {
        [key: string]: string;
    };
    engines?: {
        [key: string]: string;
    };
    os?: string[];
    cpu?: string[];
    private?: boolean;
    publishConfig?: any;
    webda?: Partial<WebdaPackageDescriptor>;
    termsOfService?: string;
    title?: string;
}
export type ModelRelation = {
    attribute: string;
    model: string;
    type: "LINK" | "LINKS_MAP" | "LINKS_ARRAY" | "LINKS_SIMPLE_ARRAY";
};
/**
 * Define the model hierarchy
 */
export type ModelsTree = {
    [key: string]: ModelsTree;
};
/**
 * A Webda module is a NPM package
 *
 * It contains one or more Modda to provide features
 */
export interface Module {
    /**
     * Services provided by the module
     */
    moddas?: {
        [key: string]: string;
    };
    /**
     * Models provided by the module
     */
    models: {
        /**
         * Models provided by the module
         */
        list: {
            [key: string]: string;
        };
        /**
         * Models hierarchy tree
         *
         * Models Graph establish the relationship between models
         * Models Tree establish the hierarchy between models classes
         */
        tree: ModelsTree;
        /**
         * Models graph
         *
         * Typescript does not have reflection, we therefore deduct the
         * relations on compilation time and inject in the module
         *
         * The parent is define by a ModelParent type on the model
         * The links are attribute of types ModelLink
         */
        graph: ModelsGraph;
        /**
         * Specific plurals for a model
         */
        plurals: {
            [key: string]: string;
        };
        /**
         * Contains the shortcut id for the models
         */
        shortIds: {
            [key: string]: string;
        };
        /**
         * Store the model attributes types
         */
        reflections: {
            [key: string]: {
                [key: string]: string;
            };
        };
    };
    /**
     * Deployers provided by the module
     *
     * @link Deployer
     */
    deployers?: {
        [key: string]: string;
    };
    /**
     * Schemas for services, deployers and coremodel
     */
    schemas?: {
        [key: string]: JSONSchema7;
    };
    /**
     * Application beans
     */
    beans?: {
        [key: string]: string;
    };
}
/**
 * Cached module is all modules discover plus local package including the sources list
 */
export interface CachedModule extends Module {
    /**
     * Contained dynamic information on the project
     * Statically capture on deployment
     */
    project: ProjectInformation;
}
export type StaticWebsite = {
    url: string;
    path?: string;
    index?: string;
    catchAll?: boolean;
};
export type UnpackedConfiguration = {
    version: 3;
    /**
     * Services configuration
     */
    services?: any;
    /**
     * Global parameters
     */
    parameters?: {
        /**
         * Trust this reverse proxies
         */
        trustedProxies?: string | string[];
        /**
         * Allowed origin for referer that match
         * any of this regexp
         *
         * {@link OriginFilter}
         */
        csrfOrigins?: string[];
        /**
         * Allow you to authorize one or several websites
         * If you use "*" then the API is open to direct call and any origins
         * You can also serve one static website by having a
         *
         * {@link WebsiteOriginFilter}
         */
        website?: string | string[];
        /**
         * Serve statically a website
         */
        static?: StaticWebsite;
        /**
         * Read from the configuration service before init
         */
        configurationService?: string;
        /**
         * Define the api url
         */
        apiUrl?: string;
        /**
         * Will not try to parse request bigger than this
         *
         * This parameter can be overriden by a direct call to
         * getHttpContext().getRawBody(xxx)
         *
         * @default 10Mb
         */
        requestLimit?: number;
        /**
         * Will not take more than this to read a request (unit: milliseconds)
         *
         * This parameter can be overriden by a direct call to
         * getHttpContext().getRawBody(undefined, xxx)
         *
         * @default 60000
         */
        requestTimeout?: number;
        /**
         * Define the default store
         */
        defaultStore?: string;
        /**
         * Define metrics
         */
        metrics?: false | {
            labels?: {
                [key: string]: string;
            };
            config?: {
                [key: string]: any;
            };
            prefix?: string;
        };
        /**
         * Allow any other type of parameters
         */
        [key: string]: any;
    };
    /**
     * OpenAPI override
     */
    openapi?: Partial<OpenAPIV3.Document>;
    /**
     * Include other configuration.json
     *
     * This allow you so share Store definition or parameters between different components
     * The configuration is merged with `deepmerge(...imports, local)`
     */
    imports?: string[];
};
export type Configuration = UnpackedConfiguration & {
    /**
     * Cached modules to avoid scanning node_modules
     * This is used by packagers
     */
    cachedModules?: CachedModule;
};
export type StoredConfiguration = Configuration;
/**
 * Return the gather information from the repository
 * @mermaid Make TypeDoc easy to use with mermaid.js
 * graph TB
 *   mermaid.js --> TypeDoc;
 */
export interface GitInformation {
    /**
     * Current commit reference
     *
     * `git rev-parse HEAD`
     */
    commit: string;
    /**
     * Current branch
     *
     * `git symbolic-ref --short HEAD`
     */
    branch: string;
    /**
     * Current commit short reference
     *
     * `git rev-parse --short HEAD`
     */
    short: string;
    /**
     * Current tag name that match the package version
     */
    tag: string;
    /**
     * Return all tags that point to the current HEAD
     *
     * `git tag --points-at HEAD`
     */
    tags: string[];
    /**
     * Current version as return by package.json with auto snapshot
     *
     * If the version return by package is not in the current `tags`, the version is
     * incremented to the next patch version with a +{date}
     *
     * Example:
     *
     * with package.json version = "1.1.0" name = "mypackage"
     * if a tag "v1.1.0" or "mypackage@1.1.0" then version = "1.1.0"
     * else version = "1.1.1+20201110163014178"
     */
    version: string;
}
/**
 * Helper to define a ServiceContrustor
 */
export interface ServiceConstructor<T extends Service> {
    new (webda: Core, name: string, params: any): T;
}
export declare enum SectionEnum {
    Moddas = "moddas",
    Deployers = "deployers",
    Beans = "beans"
}
/**
 * Webda specific metadata for the project
 */
export interface WebdaPackageDescriptor {
    /**
     * Webda namespace
     */
    namespace?: string;
    /**
     * Logo to display within the shell tty
     */
    logo?: string;
    /**
     * Service to replace default launcher
     */
    launcher?: {
        /**
         * Service to use for launch
         */
        service: string;
        /**
         * Method to use
         */
        method: string;
    };
    /**
     * Information on the workspace
     */
    workspaces?: {
        packages: string[];
        parent: PackageDescriptor;
        path: string;
    };
    [key: string]: any;
}
/**
 * Information on the whole project
 */
export interface ProjectInformation {
    /**
     * package.json information
     */
    package: PackageDescriptor;
    /**
     * Webda project information
     *
     * It is the aggregation of webda information contained in package
     * and its workspace meta
     */
    webda: WebdaPackageDescriptor;
    /**
     * Git information gathered
     */
    git: GitInformation;
    /**
     * Deployment information
     */
    deployment: {
        name: string;
        [key: string]: any;
    };
}
/**
 * Type of Section
 */
export type Section = "moddas" | "deployers" | "models" | "beans";
/**
 * Map a Webda Application
 *
 * It allows to:
 *  - Analyse imported modules
 *  - Scan code for Modda and generate the webda.config.json
 *  - Compile and Watch
 *  - Migrate from old configuration
 *  - List deployments
 *
 *
 * @category CoreFeatures
 */
export declare class Application {
    /**
     * Get Application root path
     */
    readonly appPath: string;
    /**
     * Base configuration loaded from webda.config.json
     */
    protected baseConfiguration: Configuration;
    /**
     * Current deployment
     */
    protected currentDeployment: string;
    /**
     * Contains definitions of current application
     */
    protected appModule: Module;
    /**
     * Contains already loaded modules
     */
    protected _loaded: string[];
    /**
     * Deployers type registry
     */
    protected deployers: {
        [key: string]: any;
    };
    /**
     * Moddas registry
     */
    protected moddas: {
        [key: string]: Modda;
    };
    /**
     * Models type registry
     */
    protected models: {
        [key: string]: CoreModelDefinition;
    };
    /**
     * Models graph
     */
    protected graph: ModelsGraph;
    /**
     * Models specific plurals
     */
    protected plurals: {
        [key: string]: string;
    };
    /**
     * Class Logger
     */
    protected logger: WorkerOutput;
    /**
     * Detect if running as workspace
     */
    protected workspacesPath: string;
    /**
     * When the application got initiated
     */
    protected initTime: number;
    /**
     * Direct parent of a model
     */
    protected flatHierarchy: {
        [key: string]: string;
    };
    /**
     * Configuration file
     */
    readonly configurationFile: string;
    /**
     * Current deployment file
     */
    deploymentFile: string;
    /**
     * Current application
     */
    protected static active: Application;
    /**
     *
     * @param {string} fileOrFolder to load Webda Application from
     * @param {Logger} logger
     */
    constructor(file: string, logger?: WorkerOutput);
    /**
     * Import all required modules
     */
    load(): Promise<this>;
    /**
     * Allow subclass to implement migration
     *
     * @param file
     * @returns
     */
    loadConfiguration(file: string): void;
    /**
     *
     * @param proto Prototype to send
     */
    getFullNameFromPrototype(proto: any): string;
    /**
     * Get a schema from a type
     *
     * Schema should be precomputed in the default app
     * @param type
     * @returns
     */
    getSchema(type: string): JSONSchema7;
    /**
     * Get schemas
     * @returns
     */
    getSchemas(): {
        [key: string]: JSONSchema7;
    };
    /**
     * Check if a schema exists
     * @param type
     * @returns schema name if it exists
     */
    hasSchema(type: string): boolean;
    /**
     * Get model graph
     */
    getRelations(model: string | Constructor<CoreModel> | CoreModel): ModelGraph;
    /**
     * Get the all graph
     * @returns
     */
    getGraph(): ModelsGraph;
    /**
     * Check if application has cached modules
     *
     * When deployed the application contains cachedModules in the `webda.config.json`
     * It allows to avoid the search for `webda.module.json` inside node_modules and
     * take the schema from the cached modules also
     */
    isCached(): boolean;
    /**
     * Retrieve specific webda conf from package.json
     *
     * In case of workspaces the object is combined
     */
    getPackageWebda(): WebdaPackageDescriptor;
    /**
     * Retrieve content of package.json
     */
    getPackageDescription(): PackageDescriptor;
    /**
     * Log information
     *
     * @param level to log for
     * @param args anything to display same as console.log
     */
    log(level: WorkerLogLevel, ...args: any[]): void;
    /**
     * Get current logger
     */
    getWorkerOutput(): WorkerOutput;
    /**
     * Return the current app path
     *
     * @param subpath to append to
     */
    getAppPath(subpath?: string): string;
    /**
     * Add a new service
     *
     * @param name
     * @param service
     */
    addService(name: string, service: Modda): this;
    /**
     * Register a new schema in the application
     * @param name
     * @param schema
     */
    registerSchema(name: string, schema: JSONSchema7): void;
    /**
     * Get plural of an Id
     * @param name
     * @returns
     */
    getModelPlural(name: string): string;
    /**
     *
     * @param section
     * @param name
     * @param caseSensitive
     */
    hasWebdaObject(section: Section, name: string, caseSensitive?: boolean): boolean;
    /**
     *
     * @param section
     * @param name
     * @returns
     */
    getWebdaObject(section: Section, name: string, caseSensitive?: boolean): any;
    /**
     * Get a service based on name
     *
     * @param name
     */
    getModda(name: any): Modda;
    /**
     * Return all services of the application
     */
    getModdas(): {
        [key: string]: Modda;
    };
    /**
     * Return all beans of the application
     */
    getBeans(): {
        [key: string]: string;
    };
    /**
     * Retrieve the model implementation
     *
     * @param name model to retrieve
     */
    getModel<T extends CoreModel = CoreModel>(name: string): CoreModelDefinition<T>;
    /**
     * Get all models definitions
     */
    getModels(): {
        [key: string]: CoreModelDefinition;
    };
    /**
     * Return models that do not have parents
     * @returns
     */
    getRootModels(): string[];
    /**
     * Return models that do not have parents and are exposed
     * Or specifically set as root via the Expose.root parameter
     * @returns
     */
    getRootExposedModels(): string[];
    /**
     * Return the model name for a object
     * @param object
     */
    getModelFromInstance(object: CoreModel): string | undefined;
    /**
     * Return the model name for a object
     * @param object
     */
    getModelFromConstructor(model: Constructor<CoreModel>): string | undefined;
    /**
     * Get the model name from a model or a constructor
     *
     * @param model
     * @returns longId for a model
     */
    getModelName(model: CoreModel | Constructor<CoreModel>): string | undefined;
    /**
     * Get the model hierarchy
     * @param model
     */
    getModelHierarchy(model: CoreModel | Constructor<CoreModel> | string): {
        ancestors: string[];
        children: ModelsTree;
    };
    /**
     * Get all model types with the hierarchy
     * @param model
     * @returns
     */
    getModelTypes(model: CoreModel): string[];
    /**
     * Return all deployers
     */
    getDeployers(): {
        [key: string]: Modda;
    };
    /**
     * Add a new model
     *
     * @param name
     * @param model
     */
    addModel(name: string, model: any, dynamic?: boolean): this;
    /**
     * Add a new deployer
     *
     * @param name
     * @param model
     */
    addDeployer(name: string, model: any): this;
    /**
     * Return webda current version
     *
     * @returns package version
     * @since 0.4.0
     */
    getWebdaVersion(): string;
    /**
     * Retrieve Git Repository information
     *
     * {@link GitInformation} for more details on how the information is gathered
     * @return the git information
     */
    getGitInformation(_packageName?: string, _version?: string): GitInformation;
    /**
     * Allow variable inside of string
     *
     * @param templateString to copy
     * @param replacements additional replacements to run
     */
    protected stringParameter(templateString: string, replacements?: any): any;
    /**
     * Allow variable inside object strings
     *
     * Example
     * ```js
     * replaceVariables({
     *  myobj: "${test.replace}"
     * }, {
     *  test: {
     *    replace: 'plop'
     *  }
     * })
     * ```
     * will return
     * ```
     * {
     *  myobj: 'plop'
     * }
     * ```
     *
     * By default the replacements map contains
     * ```
     * {
     *  git: GitInformation,
     *  package: 'package.json content',
     *  deployment: string,
     *  now: number,
     *  ...replacements
     * }
     * ```
     *
     * See: {@link GitInformation}
     *
     * @param object a duplicated object with replacement done
     * @param replacements additional replacements to run
     */
    replaceVariables(object: any, replacements?: any): any;
    /**
     * Get current deployment name
     */
    getCurrentDeployment(): string;
    /**
     * Return all application modules merged as one
     *
     * Used when deployed
     * @returns
     */
    getModules(): CachedModule;
    /**
     * Get application configuration
     * @returns
     */
    getConfiguration(_deployment?: string): Configuration;
    /**
     * Return current Configuration of the Application
     *
     * Same as calling
     *
     * ```js
     * getConfiguration(this.currentDeployment);
     * ```
     */
    getCurrentConfiguration(): Configuration;
    /**
     * Import a file
     *
     * If the `default` is set take this or use old format
     *
     * @param info
     */
    importFile(info: string, withExport?: boolean): Promise<any>;
    /**
     * Load local module
     */
    loadLocalModule(): Promise<void>;
    /**
     * Load the module,
     *
     * @protected
     * @ignore Useless for documentation
     */
    loadModule(module: Module, parent?: string): Promise<void>;
    /**
     * Return the full name including namespace
     *
     * In Webda the ServiceType include namespace `Webda/Store` or `Webda/Test`
     * This method will make sure the namespace is present, adding it if no '/'
     * is found in the name
     *
     * @param name
     */
    completeNamespace(name?: string): string;
    /**
     * Return current namespace
     * @returns
     */
    getNamespace(): string;
    /**
     * Get short id for a name
     * @param name if name is shortId return longId else return shortId
     * @returns
     */
    getShortId(name: string): string;
}
