/*!
 * TSBuffer Proto Generator v1.7.2
 * -----------------------------------------
 * MIT LICENSE
 * KingWorks (C) Copyright 2022
 * https://github.com/k8w/tsbuffer
 */
import { EnumTypeSchema } from 'tsbuffer-schema';
import { IntersectionTypeSchema } from 'tsbuffer-schema';
import { LiteralTypeSchema } from 'tsbuffer-schema';
import { OmitTypeSchema } from 'tsbuffer-schema';
import { PickTypeSchema } from 'tsbuffer-schema';
import ts from 'typescript';
import { TSBufferProto } from 'tsbuffer-schema';
import { TSBufferSchema } from 'tsbuffer-schema';
import { TypeReference } from 'tsbuffer-schema';
import { UnionTypeSchema } from 'tsbuffer-schema';

declare interface AstCache {
    [relativePath: string]: AstParserResult;
}

/**
 * 提取出有用的AST
 */
declare class AstParser {
    keepComment: boolean;
    pre?: {
        prePickOmitSchemas: PrePickOmitSchema[];
        preEnumSchemas: PreEnumSchema[];
    };
    constructor(options?: AstParserOptions);
    /**
     * 解析整个文件
     * @param content
     */
    parseScript(content: string, logger?: Logger | undefined): AstParserResult;
    /** 解析顶层imports */
    getScriptImports(src: ts.SourceFile): ScriptImports;
    /**
     * 将Node展平（包括Namespace里的）
     * @param node
     * @param isExport 当node是Namespace时，其外层是否处于export
     */
    getFlattenNodes(node: ts.Node, isExport?: boolean): {
        [name: string]: {
            node: ts.Node;
            comment?: string;
            isExport: boolean;
        };
    };
    node2schema(node: ts.Node, imports: ScriptImports, logger?: Logger, fullText?: string, comment?: string): PreSchema;
    /**
     * A -> A
     * A.B -> A.B
     * @param name
     */
}

declare interface AstParserOptions {
    keepComment?: boolean;
}

declare interface AstParserResult {
    [name: string]: {
        isExport: boolean;
        schema: PreSchema;
    };
}

declare interface EncodeIdItem {
    key: string;
    id: number;
}

export declare class EncodeIdUtil {
    /** 当 `genEncodeIds` 存在会增大编码大小的冗余时的事件  */
    static onGenCanOptimized?: () => void;
    /**
     * 将字符串映射为从0开始的自增数字，支持向后兼容
     * @param values object将视为 md5(JSON.stringify(obj))
     * @param compatible 需要向后兼容的结果集（新字段用新数字，旧字段ID不变）
     * @returns 返回的顺序必定与values传入的顺序相同
     */
    static genEncodeIds(values: (string | number | object)[], compatible?: EncodeIdItem[]): EncodeIdItem[];
    static getSchemaEncodeKeys(schema: TSBufferSchema): string[];
    static getKey(value: string | number | object): string;
    static getSchemaEncodeIds(schema?: TSBufferSchema): EncodeIdItem[] | undefined;
}

declare interface GenerateFileSchemaOptions {
    /** 是否解除引用（生成出不包含ReferenceType的Schema），默认为false */
    flatten?: boolean;
    /** 决定该field是否被导出，默认为导出所有export及其引用的字段
     * isUsed为true的字段，无论如何都会被导出
     */
    filter?: (info: {
        path: string;
        name: string;
        isExport: boolean;
    }) => boolean;
    /**
     * 需要向后兼容的Result
     * 生成结果：全兼容、部分兼容、完全不兼容
     * 兼容方式：旧字段ID不变，新字段换新ID
     */
    compatibleResult?: TSBufferProto;
    /**
     * logger to log
     * @defaultValue console
     */
    logger?: Logger | undefined;
}

/**
 * An abstract logger interface, which can be used to customize log behaviour.
 * Usually, you can pass `console` for convinience.
 * Or you can write your own implementation, for example, to report to a log system, or hide some log output.
 */
declare interface Logger {
    debug(...args: any[]): void;
    log(...args: any[]): void;
    warn(...args: any[]): void;
    error(...args: any[]): void;
}

declare type PreEnumSchema = {
    type: 'Enum';
    members: {
        /** Encoding identifier, generated according to the order */
        id: number;
        name: string;
        value: string | number;
    }[];
    comment?: string;
};

declare type PreKey = LiteralTypeSchema | TypeReference | UnionTypeSchema | IntersectionTypeSchema;

declare type PrePickOmitSchema = (PickTypeSchema | OmitTypeSchema) & {
    pre: {
        key: PreKey;
    };
    comment?: string;
};

/** node2Schema 第一阶段的初级 Schema */
declare type PreSchema = Exclude<TSBufferSchema, PickTypeSchema | OmitTypeSchema | EnumTypeSchema> | PrePickOmitSchema | PreEnumSchema;

export declare interface ProtoGeneratorOptions {
    /** Schema的根目录（路径在根目录以前的字符串会被相对掉） */
    baseDir: string;
    /** logger?.debug 打印调试信息 */
    verbose: boolean;
    /**
     * 读取文件的方法（用于扩展自定义文件系统）
     * @param path 于baseDir的相对路径
     */
    readFile: (path: string) => Promise<string> | string;
    /**
     * 解析Module的路径
     * @param importPath 例如 import xx from 'abcd/efg' 则 importPath 为 'abcd/efg'
     * @returns 返回 module 文件的绝对路径（不含扩展名）
     */
    resolveModule?: (importPath: string) => string;
    astCache?: AstCache;
    /**
     * Do not parse this reference targets, to implement the real reference target at runtime.
     * The schemaId would auto prepend '?'
     * For example, reference 'mongodb/ObjectId' would be converted to '?mongodb/ObjectId'.
     */
    customSchemaIds?: string[];
    /**
     * Keep comment in the output proto
     */
    keepComment?: boolean;
}

declare interface ScriptImports {
    [asName: string]: {
        path: string;
        targetName: string;
    };
}

export declare class TSBufferProtoGenerator {
    constructor(options?: Partial<ProtoGeneratorOptions>);
    /**
     * 生成FileSchema
     * 对modules（例如node_modules）的引用，也会全部转为相对路径引用
     * @param paths 于baseDir的相对路径
     * @param options
     */
    generate(paths: string | string[], options?: GenerateFileSchemaOptions): Promise<TSBufferProto>;
    /**
     * 重新生成EncodeId
     * @param output
     * @param compatibleResult
     */
    /**
     * 追加引用到的依赖
     * @param ref 被依赖的 Schema
     * @param astKey 依赖主的 astKey
     * @param name 依赖主的 name
     * @param output 输出的 Proto
     * @param astCache AST Cache
     * @param logger Logger
     * @returns
     */
}

export { }
