import { CompileOptions } from '@foundryvtt/foundryvtt-cli';
import { Plugin } from 'vite';

declare module "@foundryvtt/foundryvtt-cli" {
	type DocumentType =
		| "Actor"
		| "Adventure"
		| "Cards"
		| "ChatMessage"
		| "Combat"
		| "FogExploration"
		| "Folder"
		| "Item"
		| "JournalEntry"
		| "Macro"
		| "Playlist"
		| "RollTable"
		| "Scene"
		| "Setting"
		| "User";
	type DocumentCollection =
		| "actors"
		| "adventures"
		| "cards"
		| "messages"
		| "combats"
		| "fog"
		| "folders"
		| "items"
		| "journal"
		| "macros"
		| "playlists"
		| "tables"
		| "scenes"
		| "settings"
		| "users";
	interface PackageOptions {
		/**
		 * Whether to operate on a NeDB database, otherwise a LevelDB database is assumed.
		 * @default `false`
		 */
		nedb?: boolean;
		/**
		 * Whether the source files are in YAML format, otherwise JSON is assumed.
		 * @default `false`
		 */
		yaml?: boolean;
		/**
		 * Whether to log operation progress to the console.
		 * @default `false`
		 */
		log?: boolean;
		/**
		 * A function that is called on every entry to transform it.
		 * @default `false`
		 */
		transformEntry?: EntryTransformer;
	}
	interface CompileOptions extends PackageOptions {
		/**
		 * Whether to recurse into child directories to locate source files, otherwise only source files
		 * located in the root directory will be used.
		 * @default `false`
		 */
		recursive?: boolean;
	}
	interface ExtractOptions extends PackageOptions {
		/**
		 * Options to pass to yaml.dump when serializing Documents.
		 */
		yamlOptions?: Record<string, unknown>;
		/**
		 * Options to pass to JSON.stringify when serializing Documents.
		 */
		jsonOptions?: JSONOptions;
		/**
		 * Required only for NeDB packs in order to generate a correct key.
		 */
		documentType?: DocumentType;
		/**
		 * Delete the destination directory before unpacking.
		 */
		clean?: boolean;
		/**
		 * Required only for NeDB packs in order to generate a correct key. Can be
		 * used instead of documentType if known.
		 */
		collection?: DocumentCollection;
		/**
		 * A function that is used to generate a filename for the extracted
		 * Document. If used, the generated name must include the appropriate file
		 * extension. The generated name will be resolved against the root path
		 * provided to the operation, and the entry will be written to that
		 * resolved location.
		 */
		transformName?: NameTransformer;
	}
	interface JSONOptions {
		/**
		 * A replacer function or an array of property names in the
		 * object to include in the resulting string.
		 */
		replacer?: // biome-ignore lint/suspicious/noExplicitAny:
			| ((this: any, key: string, value: any) => any)
			| (string | number)[]
			| null
			| undefined;
		/** A number of spaces or a string to use as indentation. */
		space?: string | number | undefined;
	}

	// biome-ignore lint/suspicious/noConfusingVoidType:
	type EntryTransformer = (entry: object) => Promise<false | void>;
	// biome-ignore lint/suspicious/noConfusingVoidType:
	type NameTransformer = (entry: object) => Promise<string | void>;
	type HierarchyApplyCallback = (
		doc: object,
		collection: DocumentCollection,
		options?: object,
		// biome-ignore lint/suspicious/noConfusingVoidType:
	) => Promise<object | void>;
	type HierarchyMapCallback = (
		entry: unknown,
		collection: DocumentCollection,
	) => Promise<unknown>;

	/**
	 * Compile source files into a compendium pack.
	 * @param src   The directory containing the source files.
	 * @param dest  The target compendium pack. This should be a directory for LevelDB packs, or a .db file for
	 *              NeDB packs.
	 */
	function compilePack(
		src: string,
		dest: string,
		{
			nedb = false,
			yaml = false,
			recursive = false,
			log = false,
			transformEntry,
		}: CompileOptions = {},
	): Promise<void>;

	/**
	 * Extract a NeDB compendium pack into individual source files for each primary Document.
	 * @param pack  The source compendium pack.
	 * @param dest  The root output directory.
	 */
	function extractPack(
		src: string,
		dest: string,
		{
			nedb = false,
			yaml = false,
			yamlOptions = {},
			jsonOptions = {},
			log = false,
			documentType,
			collection,
			clean,
			transformEntry,
			transformName,
		}: ExtractOptions = {},
	): Promise<void>;
}

type Compatibility = {
	minimum?: number | string;
	verified?: number | string;
	maximum?: number | string;
};
type Relationship = {
	id: string;
	manifest?: string;
	compatibility?: Compatibility;
};
type Language = {
	lang: string;
	name: string;
	path: string;
	flags?: Record<string, unknown>;
};
type PackFolder = {
	name: string;
	sorting?: "m" | "a";
	color?: string;
	packs?: string[];
	folders?: PackFolder[];
};

type FoundryManifest = {
	id: string;
	title: string;
	description: string;
	version: string;
	compatibility?: Compatibility;
	authors?: {
		name: string;
		email?: string;
		discord?: string;
		url?: string;
		flags?: Record<string, unknown>;
	}[];
	scripts?: string[];
	esmodules?: string[];
	styles?: ({ src: string; layer: string | null } | string)[];
	packs?: {
		name: string;
		label: string;
		system?: string;
		path?: string;
		type: string;
		private?: boolean;
		flags?: Record<string, unknown>;
	}[];
	packFolders?: PackFolder[];
	relationships?: {
		requires?: Relationship[];
		recommends?: Relationship[];
		systems?: Relationship[];
	};
	languages?: Language[];
	documentTypes?: Record<
		string,
		Record<
			string,
			{ htmlFields?: string[]; filePathFields?: Record<string, string[]> }
		>
	>;
	socket?: boolean;
	media?: {
		type: string;
		url: string;
		thumbnail?: string;
		flags?: Record<string, unknown>;
	}[];
	initiative?: string | null;
	grid?: {
		type?: number;
		distance?: number;
		units?: string;
		diagonals?: number;
	};
	primaryTokenAttribute?: string;
	secondaryTokenAttribute?: string;
	url?: string;
	manifest?: string;
	download?: string;
	protected?: boolean;
	background?: string;
	flags?: {
		hotReload?: {
			extensions: string[];
			paths?: string[];
		};
		[key: string]: unknown | undefined;
	};
};

type PackOptions = CompileOptions;
interface FoundryVTTPluginConfig {
    /**
     * Top-level keys to replace in the manifest data. A shallow merge is used.
     * Intended for replacing manifest and download links in ci builds.
     * @default `{}`
     */
    substitutions?: Record<string, unknown>;
    /**
     * Package type
     * @default `"system"`
     */
    type?: "system" | "module";
    /**
     * Source directory for pack files
     * @default `"src/packs"`
     */
    packDir?: string;
    /**
     * Whether to attempt to build configured compendium packs
     * @default `true`
     */
    buildPacks?: boolean;
    /**
     * Options passed through to the pack compile operation
     * @default `{ yaml: true }`
     */
    packOptions?: PackOptions;
}
/**
 * Configure foundry hotReload, write pack files and write the manifest with
 * substitution.
 * @param manifest  Foundry package manifest data.  This data will be written
 *                  to the outDir as the package manifest.
 */
declare function foundryvtt(manifest: FoundryManifest, { substitutions, type, packDir, buildPacks, packOptions, }?: FoundryVTTPluginConfig): Plugin;

// @ts-ignore
export = foundryvtt;
export type { FoundryVTTPluginConfig, PackOptions };
