import libCoverage, { FileCoverage, FileCoverageData, CoverageMap } from 'istanbul-lib-coverage';
import { ProxifiedModule } from 'magicast';
import { BaseCoverageProvider, CoverageProvider, Vitest, Vite, ReportContext } from 'vitest/node';

interface GeneratorOptions {
    /**
     * Optional string to add as a block comment at the start of the output file.
     */
    auxiliaryCommentBefore?: string | undefined;

    /**
     * Optional string to add as a block comment at the end of the output file.
     */
    auxiliaryCommentAfter?: string | undefined;

    /**
     * Function that takes a comment (as a string) and returns true if the comment should be included in the output.
     * By default, comments are included if `opts.comments` is `true` or if `opts.minifed` is `false` and the comment
     * contains `@preserve` or `@license`.
     */
    shouldPrintComment?(comment: string): boolean;

    /**
     * Attempt to use the same line numbers in the output code as in the source code (helps preserve stack traces).
     * Defaults to `false`.
     */
    retainLines?: boolean | undefined;

    /**
     * Should comments be included in output? Defaults to `true`.
     */
    comments?: boolean | undefined;

    /**
     * Set to true to avoid adding whitespace for formatting. Defaults to the value of `opts.minified`.
     */
    compact?: boolean | "auto" | undefined;

    /**
     * Should the output be minified. Defaults to `false`.
     */
    minified?: boolean | undefined;

    /**
     * Set to true to reduce whitespace (but not as much as opts.compact). Defaults to `false`.
     */
    concise?: boolean | undefined;

    /**
     * The type of quote to use in the output. If omitted, autodetects based on `ast.tokens`.
     */
    quotes?: "single" | "double" | undefined;

    /**
     * Used in warning messages
     */
    filename?: string | undefined;

    /**
     * Enable generating source maps. Defaults to `false`.
     */
    sourceMaps?: boolean | undefined;

    /**
     * The filename of the generated code that the source map will be associated with.
     */
    sourceMapTarget?: string | undefined;

    /**
     * A root for all relative URLs in the source map.
     */
    sourceRoot?: string | undefined;

    /**
     * The filename for the source code (i.e. the code in the `code` argument).
     * This will only be used if `code` is a string.
     */
    sourceFileName?: string | undefined;

    /**
     * Set to true to run jsesc with "json": true to print "\u00A9" vs. "©";
     */
    jsonCompatibleStrings?: boolean | undefined;
}

interface StartOfSourceMap {
    file?: string;
    sourceRoot?: string;
}

interface RawSourceMap extends StartOfSourceMap {
    version: string;
    sources: string[];
    names: string[];
    sourcesContent?: string[];
    mappings: string;
}

interface InstrumenterOptions {
    coverageVariable: string;
    preserveComments: boolean;
    compact: boolean;
    esModules: boolean;
    autoWrap: boolean;
    produceSourceMap: boolean;
    sourceMapUrlCallback(filename: string, url: string): void;
    debug: boolean;
    coverageGlobalScope?: string;
    coverageGlobalScopeFunc?: boolean;
    ignoreClassMethods?: string[];
    parserPlugins?: any[];
    generatorOpts?: GeneratorOptions;
}

type InstrumenterCallback = (error: Error | null, code: string) => void;

declare class Instrumenter {
    fileCoverage: FileCoverage;
    sourceMap: RawSourceMap | null;
    opts: InstrumenterOptions;

    constructor(options?: Partial<InstrumenterOptions>);

    normalizeOpts(options?: Partial<InstrumenterOptions>): InstrumenterOptions;

    instrumentSync(
        code: string,
        filename: string,
        inputSourceMap?: RawSourceMap,
    ): string;

    instrument(
        code: string,
        filenameOrCallback: string | InstrumenterCallback,
        callback?: InstrumenterCallback,
        inputSourceMap?: RawSourceMap,
    ): void;

    lastFileCoverage(): FileCoverageData;
    lastSourceMap(): RawSourceMap;
}

declare class IstanbulCoverageProvider extends BaseCoverageProvider implements CoverageProvider {
	name: "istanbul";
	version: string;
	instrumenter: Instrumenter;
	private transformedModuleIds;
	initialize(ctx: Vitest): void;
	requiresTransform(id: string): boolean;
	onFileTransform(sourceCode: string, id: string, pluginCtx: Vite.Rollup.TransformPluginContext): {
		code: string;
		map: any;
	} | undefined;
	createCoverageMap(): libCoverage.CoverageMap;
	generateCoverage({ allTestsRun }: ReportContext): Promise<CoverageMap>;
	generateReports(coverageMap: CoverageMap, allTestsRun: boolean | undefined): Promise<void>;
	parseConfigModule(configFilePath: string): Promise<ProxifiedModule<any>>;
	private getCoverageMapForUncoveredFiles;
	onEnabled(): void;
	private invalidateTree;
}

export { IstanbulCoverageProvider };
