import Crowdin, { SourceFilesModel, TranslationStatusModel } from '@crowdin/crowdin-api-client';
import { Request } from 'express';
import { CrowdinClientRequest, ModuleKey } from '../../types';
import { IntegrationSyncedData, JobClient, JobStoreType } from './util/types';
import { AppModuleError, AppUserModuleError } from '../../util/logger';
export interface IntegrationLogic extends ModuleKey {
    /**
     * Customize your app login form
     */
    loginForm?: LoginForm;
    /**
     * Define login process via OAuth2 protocol
     */
    oauthLogin?: OAuthLogin;
    /**
     * name of the root folder in Crowdin where files from integration will be stored, default your app name, will be ignored in case if {@link withRootFolder} is false
     */
    appFolderName?: string;
    /**
     * flag that defines if the app should have a dedicated root folder in Crowdin files, default 'false'
     */
    withRootFolder?: boolean;
    /**
     * Validate integration settings before saving
     */
    validateSettings?: ({ client, credentials, settings, }: {
        client: Crowdin;
        credentials: any;
        settings: any;
    }) => Promise<{
        [key: string]: string;
    } | null>;
    /**
     * function which will be used to check connection with integration service
     */
    checkConnection?: (credentials: any) => Promise<void>;
    /**
     * function to get crowdin files that are related with this integration
     */
    getCrowdinFiles?: (options: {
        projectId: number;
        client: Crowdin;
        rootFolder?: SourceFilesModel.Directory;
        settings?: any;
        mode?: CrowdinFilesLoadMode;
    }) => Promise<TreeItem[]>;
    /**
     * Match Crowdin files to integration files or vice versa.
     */
    matchCrowdinFilesToIntegrationFiles?: ({ projectId, client, credentials, crowdinFiles, integrationFiles, settings, rootFolder, syncedData, }: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        crowdinFiles?: UpdateIntegrationRequest;
        integrationFiles?: IntegrationFile[];
        settings?: any;
        rootFolder?: SourceFilesModel.Directory;
        syncedData?: IntegrationSyncedData | undefined;
    }) => Promise<IntegrationFile[] | UpdateIntegrationRequest | MatchingResult<IntegrationFile[] | UpdateIntegrationRequest>>;
    /**
     * function to get data from integration
     */
    getIntegrationFiles: (options: {
        credentials: any;
        client?: Crowdin;
        projectId?: number;
        settings?: any;
        parentId?: any;
        search?: any;
        page?: any;
        paginationData?: any;
    }) => Promise<TreeItem[] | ExtendedResult<TreeItem[]>>;
    /**
     * function to update crowdin files (e.g. pull integration data to crowdin source files)
     */
    updateCrowdin: ({ projectId, client, credentials, request, rootFolder, settings, uploadTranslations, job, excludedTargetLanguages, }: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        request: IntegrationFile[];
        rootFolder?: SourceFilesModel.Directory;
        settings?: any;
        uploadTranslations?: boolean;
        job: JobClient;
        excludedTargetLanguages?: string[];
    }) => Promise<void | ExtendedResult<void>>;
    /**
     * function to update integration content (e.g. load crowdin translations and push them to integration service)
     */
    updateIntegration: ({ projectId, client, credentials, request, rootFolder, settings, job, }: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        request: UpdateIntegrationRequest;
        rootFolder?: SourceFilesModel.Directory;
        settings?: any;
        job: JobClient;
    }) => Promise<void | ExtendedResult<void>>;
    /**
     * Store to use for memorizing job data
     */
    jobStoreType?: JobStoreType;
    /**
     * function to define configuration(settings) modal for you app (by default app will not have any custom settings)
     */
    getConfiguration?: (options: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        settings: any;
        clientId: string;
    }) => Promise<FormEntity[]>;
    /**
     * function to normalize saved settings
     */
    normalizeSettings?: ({ settings, credentials, client, }: {
        settings: FormEntity[];
        credentials: any;
        client?: Crowdin;
    }) => Promise<FormEntity[]>;
    /**
     * Logout hook for cleanup logic
     */
    onLogout?: (options: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        settings?: any;
    }) => Promise<void>;
    /**
     * flag to turn on auto reload of the tree whenever user updates the configuration
     */
    reloadOnConfigSave?: boolean;
    /**
     * define info modal (help section) for you app (by default app will not have own info section)
     */
    infoModal?: {
        title: string;
        content: string;
    };
    /**
     * background jobs that will be executed for each crowdin project and user
     */
    cronJobs?: CronJob[];
    /**
     * Enable new file sync when syncing via cron or webhook
     */
    syncNewElements?: {
        crowdin: boolean;
        integration: boolean;
    };
    withCronSync?: {
        crowdin: boolean;
        integration: boolean;
    };
    withWebhookSync?: {
        crowdin: boolean;
        integration: boolean;
    };
    /**
     * Schedule value that will be auto-applied when user enables Auto Sync while current schedule is disabled.
     * Supported values are: '0', '1', '3', '6', '12', '24'.
     * Use '0' to disable this auto-apply behavior.
     * @default '12'
     */
    autoEnableScheduleOnAutoSync?: '0' | '1' | '3' | '6' | '12' | '24';
    /**
     * Enable file filtering
     */
    filtering?: {
        crowdinLanguages?: boolean;
        /**
         * Configuration for integration file filtering
         */
        integrationFilterConfig?: any;
        /**
         * Enable file status filtering
         */
        integrationFileStatus?: {
            /**
             * Enable file filtering by "isNew" status
             */
            isNew?: boolean;
            /**
             * Enable file filtering by "isUpdated" status
             */
            isUpdated?: boolean;
            /**
             * Enable file filtering by "failed" status
             */
            failed?: boolean;
            /**
             * Enable file filtering by "notSynced" status
             */
            notSynced?: boolean;
            /**
             * Enable file filtering by "synced" status
             */
            synced?: boolean;
        };
    };
    /**
     * Enable integration folder open event
     */
    integrationOneLevelFetching?: boolean;
    /**
     * Concurrency limit for snapshot fetching when integrationOneLevelFetching is enabled.
     * Controls how many folders are fetched in parallel at each level of the tree.
     * @default 1
     */
    snapshotFetchConcurrency?: number;
    /**
     * Enable integration search event
     */
    integrationSearchListener?: boolean;
    /**
     * Enable integration next page event
     */
    integrationPagination?: boolean;
    /**
     * Enable progressive loading for Crowdin files (directories first, then files).
     */
    progressiveCrowdinFilesLoading?: boolean;
    /**
     * Enable the option to upload translations to crowdin that are already present in the integration.
     */
    uploadTranslations?: boolean;
    /**
     * Force sync translations from Crowdin to integration regardless of etag.
     */
    forcePushTranslations?: boolean;
    /**
     * Force sync sources from integration to Crowdin.
     */
    forcePushSources?: boolean;
    /**
     * Enable the option to upload file for translation into selected languages.
     */
    excludedTargetLanguages?: boolean;
    /**
     * function to update target languages for existing Crowdin files.
     */
    updateFilesTargetLanguages?: ({ projectId, client, fileIds, excludedTargetLanguages, }: {
        projectId: number;
        client: Crowdin;
        fileIds: number[];
        excludedTargetLanguages: string[];
    }) => Promise<void>;
    /**
     * Enable the option to add 'Exclude paths' and 'Include paths' text fields to integration settings
     */
    filterByPathIntegrationFiles?: boolean;
    /**
     * function to get crowdin file translation progress
     */
    getFileProgress?: (options: {
        projectId: number;
        client: Crowdin;
        fileId: number;
    }) => Promise<{
        [key: number]: TranslationStatusModel.LanguageProgress[];
    }>;
    /**
     * Register Crowdin webhook to get notified when translations are ready
     */
    webhooks?: Webhooks;
    /**
     * define a notification for your application at the top of the screen
     */
    notice?: {
        title: string;
        content: string;
        type: NoticeType;
        icon: boolean;
        close: boolean;
    };
    /**
     * Skip integration nodes
     */
    skipIntegrationNodes?: SkipIntegrationNodes;
    /**
     * Configuration for toggling skipIntegrationNodes functionality with custom title and description
     */
    skipIntegrationNodesToggle?: {
        title: string;
        description: string;
        value: boolean;
    };
    /**
     * Async progress checking time interval to update job progress, im ms.
     *
     * Default 1000
     */
    asyncProgress?: {
        checkInterval?: number;
    };
    /**
     * The duration for storing user errors, default is 30 days.
     */
    userErrorLifetimeDays?: number;
    /**
     * When true, folder filtering during automatic translation sync is bypassed, and the file tree is returned unchanged.
     */
    skipAutoSyncFoldersFilter?: boolean;
}
export interface LoginForm {
    fields: FormEntity[];
    /**
     * Override to implement request for retrieving access token (and refresh token if 'refresh' is enabled)
     */
    performGetTokenRequest?: (fieldsCredentials: any) => Promise<LoginFormTokenResponse>;
    /**
     * Override to implement request for refreshing token (only if 'refresh' is enabled)
     */
    performRefreshTokenRequest?: (currentCredentials: any) => Promise<LoginFormTokenResponse>;
    /**
     * default 'false' which means that the access token has no expiration date
     */
    refresh?: boolean;
}
export interface OAuthLogin {
    /**
     * Extra field for login form
     */
    loginFields?: FormField[];
    /**
     * Authorization url (e.g. https://github.com/login/oauth/authorize or https://accounts.google.com/o/oauth2/v2/auth)
     */
    authorizationUrl?: string;
    /**
     * Authorization url getter
     */
    getAuthorizationUrl?: (options: {
        redirectUrl: string;
        loginForm: any;
    }) => string;
    /**
     * Access token url (e.g. https://github.com/login/oauth/access_token)
     */
    accessTokenUrl: string;
    /**
     * Url to refresh token, default will use {@link accessTokenUrl}. Needed when {@link refresh} is enabled
     */
    refreshTokenUrl?: string;
    mode?: 'standard' | 'polling';
    /**
     * The scopes of access, usually expressed as a list of space-delimited, case-sensitive strings
     */
    scope?: string;
    /**
     * Client id
     */
    clientId: string;
    /**
     * Client secret
     */
    clientSecret: string;
    /**
     * default '/oauth/code'
     */
    redirectUriRoute?: string;
    /**
     * request/response fields mapping
     */
    fieldsMapping?: {
        /**
         * default 'client_id'
         */
        clientId?: string;
        /**
         * default 'client_secret'
         */
        clientSecret?: string;
        /**
         * default 'scope'
         */
        scope?: string;
        /**
         * default 'redirect_uri'
         */
        redirectUri?: string;
        /**
         * default 'code'
         */
        code: string;
        /**
         * default 'access_token'
         */
        accessToken?: string;
        /**
         * default 'refresh_token'
         */
        refreshToken?: string;
        /**
         * default 'expires_in'
         */
        expiresIn?: string;
        /**
         * default 'state'
         */
        state?: string;
    };
    /**
     * default 'false' which means that the access token has no expiration date
     */
    refresh?: boolean;
    /**
     * Additional URL parameters for authorizarion url
     */
    extraAutorizationUrlParameters?: {
        [key: string]: string;
    };
    /**
     * Additional parameters for access token request
     */
    extraAccessTokenParameters?: {
        [key: string]: any;
    };
    /**
     * Additional parameters for refresh token request
     */
    extraRefreshTokenParameters?: {
        [key: string]: any;
    };
    /**
     * Override to implement request for retrieving access token (and refresh token if 'refresh' is enabled)
     */
    performGetTokenRequest?: (options: {
        code: string;
        query: {
            [key: string]: any;
        };
        url: string;
        redirectUri: string;
        loginForm?: any;
    }) => Promise<any>;
    /**
     * Override to implement request for refreshing token (only if 'refresh' is enabled)
     */
    performRefreshTokenRequest?: (options: {
        credentials: any;
        loginForm?: any;
    }) => Promise<any>;
}
export type CrowdinFilesLoadMode = 'directories' | 'files';
export interface BaseTreeItem {
    id: string;
    name: string;
    parentId?: string;
    nodeType?: IntegrationTreeElementType;
    customContent?: string;
    labels?: LabelTreeElement[];
    disabled?: boolean;
    tooltip?: string;
    path?: string;
    type?: string;
    syncedAt?: string;
}
export interface File extends BaseTreeItem {
    type: SourceFilesModel.FileType;
    failed?: boolean;
    excludedTargetLanguages?: string[];
}
export type Folder = BaseTreeItem;
export type TreeItem = File | Folder;
/**
 * 0 - folder
 * 1 - file
 * 2 - branch
 */
type IntegrationTreeElementType = '0' | '1' | '2';
export type FormEntity = FormField | FormDelimiter;
export interface FormDelimiter {
    label?: string;
    labelHtml?: string;
    category?: string;
}
export interface FormField {
    key: string;
    helpText?: string;
    helpTextHtml?: string;
    label: string;
    type?: 'text' | 'password' | 'checkbox' | 'select' | 'textarea' | 'file' | 'notice';
    defaultValue?: any;
    /**
     * only for select
     */
    isMulti?: boolean;
    /**
     * only for select
     */
    isSearchable?: boolean;
    /**
     * only for select
     */
    options?: {
        label: string;
        value: string;
    }[];
    /**
     * only for type file
     */
    accept?: string;
    /**
     * field dependency settings
     */
    dependencySettings?: string;
    /**
     * only for notice type
     */
    noticeType?: string;
    /**
     * only for notice type
     */
    noIcon?: boolean;
    category?: string;
    position?: number;
}
type NoticeType = 'info' | 'warning' | 'danger' | 'success' | 'error' | 'dataLostWarning';
export interface IntegrationCredentials {
    id: string;
    credentials: any;
    crowdinId: string;
    managers?: any;
}
export interface IntegrationConfig {
    id: number;
    integrationId: string;
    crowdinId: string;
    config: any;
}
export interface IntegrationFile {
    id: string;
    name: string;
    type: SourceFilesModel.FileType;
    parentId: string;
    nodeType?: IntegrationTreeElementType;
}
export interface UpdateIntegrationRequest {
    [fileId: string]: string[];
}
export interface UpdateTargetLanguagesRequest {
    fileIds: number[];
    languages: string[];
}
export interface IntegrationRequest extends CrowdinClientRequest {
    integrationCredentials: any;
    integrationSettings?: any;
    canForceIntegrationLogout?: boolean;
}
export interface CronJob {
    task: (options: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        rootFolder?: SourceFilesModel.Directory;
        settings?: any;
    }) => Promise<void>;
    expression: string;
}
export interface ExtendedResult<T> {
    data?: T;
    message?: string;
    stopPagination?: boolean;
}
export interface MatchingResult<T> {
    data: T;
    errors?: Error[] | AppModuleError[] | AppUserModuleError[];
}
type LabelTreeElementType = 'primary' | 'secondary' | 'success' | 'warning' | 'info' | 'danger' | 'dark' | 'light';
export interface LabelTreeElement {
    text: string;
    type?: LabelTreeElementType;
    tooltip?: string;
    color?: string;
}
export declare enum Provider {
    CROWDIN = "crowdin",
    INTEGRATION = "integration"
}
export interface IntegrationSyncSettings {
    id: number;
    files?: any;
    integrationId: string;
    crowdinId: string;
    provider: Provider;
}
export interface IntegrationFilesSnapshot {
    id: number;
    files?: any;
    integrationId: string;
    crowdinId: string;
    provider: Provider;
}
export interface IntegrationWebhooks {
    id: number;
    fileId: number;
    integrationId: string;
    crowdinId: string;
    provider: Provider;
}
export interface SkipIntegrationNodes {
    fileNamePattern?: string;
    folderNamePattern?: string;
}
export interface Webhooks {
    crowdinWebhookUrl?: string;
    integrationWebhookUrl?: string;
    urlParam?: string;
    crowdinWebhooks?: (options: {
        client: Crowdin;
        projectId: number;
        available: boolean;
        settings?: AppSettings;
    }) => Promise<void>;
    integrationWebhooks?: (options: {
        credentials: any;
        urlParam: string;
        available: boolean;
        settings?: AppSettings;
        syncSettings?: any;
    }) => Promise<void>;
    crowdinWebhookInterceptor?: (options: {
        projectId: number;
        client: Crowdin;
        rootFolder?: SourceFilesModel.Directory;
        settings?: any;
        syncSettings?: any;
        webhookRequest?: any;
    }) => Promise<UpdateIntegrationRequest>;
    integrationWebhookInterceptor?: (options: {
        projectId: number;
        client: Crowdin;
        credentials: any;
        rootFolder?: SourceFilesModel.Directory;
        settings?: AppSettings;
        syncSettings?: any;
        webhookRequests?: any;
    }) => Promise<IntegrationFile[]>;
    queueUrl: string;
}
export declare enum SyncCondition {
    ALL = 0,
    TRANSLATED = 1,
    APPROVED = 2
}
export declare enum SyncSchedule {
    DISABLED = 0,
    ACTIVE
}
export type Payload = {
    event: string;
    projectId: string;
    language: string;
    fileId: string;
};
export type WebhookUrlParams = {
    projectId: number;
    crowdinId: string;
    clientId: string;
};
export interface UpdateCrowdinWebhookPayloadsArgs {
    integration: IntegrationLogic;
    webhookData: any;
    req: Request[];
}
export interface FilterSyncFilesArgs {
    projectId: number;
    client: Crowdin;
    events: Payload[];
    syncFileSettings: UpdateIntegrationRequest;
    settings: AppSettings;
}
export interface AppSettings {
    schedule?: number;
    condition?: number;
    'new-crowdin-files'?: boolean;
    'new-integration-files'?: boolean;
    [key: string]: any;
}
interface LoginFormTokenResponse {
    access_token: string;
    expires_in: number;
    refresh_token: string;
}
export declare enum DefaultCategory {
    GENERAL = "General Settings",
    SYNC = "Sync settings",
    ADVANCED = "Advanced"
}
export {};
