import { YankiConnectOptions, YankiFetchAdapter, YankiParamsForAction } from "yanki-connect";
import { PartialDeep, Simplify } from "type-fest";

//#region src/lib/model/model.d.ts
declare const yankiModels: [{
  readonly cardTemplates: [{
    readonly Back: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}";
    readonly Front: "{{Front}}";
    readonly YankiNamespace: "{{YankiNamespace}}";
  }];
  readonly inOrderFields: ["Front", "Back", "YankiNamespace"];
  readonly modelName: "Yanki - Basic";
}, {
  readonly cardTemplates: [{
    readonly Back: "{{cloze:Front}}<br>\n{{Back}}";
    readonly Front: "{{cloze:Front}}";
    readonly YankiNamespace: "{{YankiNamespace}}";
  }];
  readonly inOrderFields: ["Front", "Back", "YankiNamespace"];
  readonly isCloze: true;
  readonly modelName: "Yanki - Cloze";
}, {
  readonly cardTemplates: [{
    readonly Back: "{{Front}}\n\n<hr id=answer>\n\n{{type:Back}}";
    readonly Front: "{{Front}}\n\n{{type:Back}}";
    readonly YankiNamespace: "{{YankiNamespace}}";
  }];
  readonly inOrderFields: ["Front", "Back", "YankiNamespace"];
  readonly modelName: "Yanki - Basic (type in the answer)";
}, {
  readonly cardTemplates: [{
    readonly Back: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}{{#Extra}}\n\n<hr>\n\n{{Extra}}{{/Extra}}";
    readonly Front: "{{Front}}";
    readonly YankiNamespace: "{{YankiNamespace}}";
  }, {
    readonly Back: "{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}{{#Extra}}\n\n<hr>\n\n{{Extra}}{{/Extra}}";
    readonly Front: "{{Back}}";
    readonly YankiNamespace: "{{YankiNamespace}}";
  }];
  readonly inOrderFields: ["Front", "Back", "Extra", "YankiNamespace"];
  readonly modelName: "Yanki - Basic (and reversed card with extra)";
}];
type YankiModelName = (typeof yankiModels)[number]['modelName'];
//#endregion
//#region src/lib/model/note.d.ts
type YankiNote = Simplify<Omit<YankiParamsForAction<'addNote'>['note'], 'fields' | 'modelName' | 'options'> & {
  cards?: number[];
  fields: {
    Back: string;
    Extra?: string;
    Front: string;
    YankiNamespace: string;
  };
  modelName: YankiModelName;
  noteId: number | undefined;
}>;
//#endregion
//#region src/lib/shared/types.d.ts
type FetchAdapter = YankiFetchAdapter;
type ManageFilenames = 'off' | 'prompt' | 'response';
type SyncMediaAssets = 'all' | 'local' | 'off' | 'remote';
type FileAdapter = {
  readFile(filePath: string): Promise<string>;
  readFileBuffer(filePath: string): Promise<Uint8Array>;
  rename(oldPath: string, newPath: string): Promise<void>;
  stat(filePath: string): Promise<{
    ctimeMs: number;
    mtimeMs: number;
    size: number;
  }>;
  writeFile(filePath: string, data: string): Promise<void>;
};
type GlobalOptions = {
  /**
   * Used for wiki link resolution
   */
  allFilePaths: string[];
  ankiConnectOptions: YankiConnectOptions;
  /**
   * Automatically sync any changes to AnkiWeb after Yanki has finished syncing
   * locally. If false, only local Anki data is updated and you must manually
   * invoke a sync to AnkiWeb. This is the equivalent of pushing the "sync"
   * button in the Anki app.
   */
  ankiWeb: boolean;
  /**
   * Override where "/" should resolve to... useful in Obsidian to set the vault
   * path as the "root"
   */
  basePath: string | undefined;
  /**
   * Run Anki's "Check Database" command after sync updates that might produce
   * card corruption
   */
  checkDatabase: boolean;
  cwd: string;
  dryRun: boolean;
  /**
   * Exposed for Obsidian, currently only used for getting URL content hashes
   * and inferring MIME types of URLs without extensions. Note that
   * ankiConnectOptions ALSO has a fetch adapter option specifically for
   * communicating with AnkiConnect.
   */
  fetchAdapter: FetchAdapter | undefined;
  fileAdapter: FileAdapter | undefined;
  manageFilenames: ManageFilenames;
  /**
   * Only applies if manageFilenames is `true`. Will _not_ truncate
   * user-specified file names in other cases.
   */
  maxFilenameLength: number;
  namespace: string; /** Ensures that wiki-style links work correctly */
  obsidianVault: string | undefined; /** Exposed for testing only */
  resolveUrls: boolean;
  /**
   * Whether to treat single newlines in Markdown as line breaks in the
   * resulting HTML (Obsidian has an application-level setting for this)
   */
  strictLineBreaks: boolean;
  /**
   * Only consider exact noteId matches between the local and remote copies to
   * be equivalent, don't match local notes with "orphaned" remote notes based
   * on content
   */
  strictMatching: boolean; /** Sync image, video, and audio assets to Anki's media storage system */
  syncMediaAssets: SyncMediaAssets;
};
//#endregion
//#region src/lib/actions/clean.d.ts
type CleanOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun' | 'namespace'>;
declare const defaultCleanOptions: CleanOptions;
type CleanResult = Simplify<Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'> & {
  deletedDecks: string[];
  deletedMedia: string[];
  deletedNotes: YankiNote[];
  duration: number;
}>;
/**
 * Deletes all remote notes in Anki associated with the given namespace.
 *
 * Use with significant caution. Mostly useful for testing.
 *
 * @returns The IDs of the notes that were deleted
 * @throws {Error} If Anki is unreachable or another error occurs during
 *   deletion.
 */
declare function cleanNotes(options?: PartialDeep<CleanOptions>): Promise<CleanResult>;
declare function formatCleanResult(result: CleanResult, verbose?: boolean): string;
//#endregion
//#region src/lib/actions/list.d.ts
type ListOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'namespace'>;
declare const defaultListOptions: ListOptions;
type ListResult = {
  duration: number;
  namespace: string;
  notes: YankiNote[];
};
/**
 * Description List notes currently in Anki...
 */
declare function listNotes(options?: PartialDeep<ListOptions>): Promise<ListResult>;
declare function formatListResult(result: ListResult): string;
//#endregion
//#region src/lib/actions/load-local-notes.d.ts
type LoadOptions = Pick<GlobalOptions, 'allFilePaths' | 'basePath' | 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'strictLineBreaks' | 'syncMediaAssets'>;
type LocalNote = {
  filePath: string;
  filePathOriginal: string;
  markdown: string;
  note: YankiNote;
};
//#endregion
//#region src/lib/actions/rename.d.ts
type RenameNotesOptions = Pick<GlobalOptions, 'dryRun' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength'
/**
 * Included because this can technically change the content of the "first
 * line" of a card
 */
| 'strictLineBreaks'>;
type RenameFilesResult = {
  dryRun: boolean;
  notes: LocalNote[];
};
type RenameFilesOptions = Simplify<LoadOptions & RenameNotesOptions>;
declare const defaultRenameFilesOptions: RenameFilesOptions;
/**
 * Currently used for testing and by `yanki-obsidian`.
 */
declare function renameFiles(allLocalFilePaths: string[], options: Partial<RenameFilesOptions>): Promise<RenameFilesResult>;
//#endregion
//#region src/lib/actions/style.d.ts
type SetStyleOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'dryRun'> & {
  css: string;
};
declare const defaultSetStyleOptions: SetStyleOptions;
type SetStyleResult = Simplify<Pick<GlobalOptions, 'ankiWeb' | 'dryRun'> & {
  duration: number;
  models: Array<{
    action: 'unchanged' | 'updated';
    name: string;
  }>;
}>;
type GetStyleOptions = Pick<GlobalOptions, 'ankiConnectOptions'>;
declare const defaultGetStyleOptions: GetStyleOptions;
declare function getStyle(options: PartialDeep<GetStyleOptions>): Promise<string>;
declare function setStyle(options?: PartialDeep<SetStyleOptions>): Promise<SetStyleResult>;
declare function formatSetStyleResult(result: SetStyleResult, verbose?: boolean): string;
//#endregion
//#region src/lib/actions/sync-notes.d.ts
type SyncedNote = {
  action: 'ankiUnreachable' | 'created' | 'deleted' | 'matched' | 'unchanged' | 'updated';
  note: YankiNote;
};
type SyncNotesOptions = Pick<GlobalOptions, 'ankiConnectOptions' | 'ankiWeb' | 'checkDatabase' | 'dryRun' | 'fileAdapter' | 'namespace' | 'strictMatching'>;
declare const defaultSyncNotesOptions: SyncNotesOptions;
type SyncNotesResult = Simplify<Pick<GlobalOptions, 'ankiWeb' | 'dryRun' | 'namespace'> & {
  deletedDecks: string[];
  deletedMedia: string[];
  duration: number;
  fixedDatabase: boolean;
  reuploadedMedia: string[];
  synced: SyncedNote[];
}>;
/**
 * Syncs local notes to Anki.
 *
 * @param allLocalNotes All the YankiNotes to sync
 *
 * @returns The synced notes (with new IDs where applicable), plus some stats
 *   about the sync
 * @throws {Error} For various reasons...
 */
declare function syncNotes(allLocalNotes: YankiNote[], options?: PartialDeep<SyncNotesOptions>): Promise<SyncNotesResult>;
//#endregion
//#region src/lib/actions/sync-files.d.ts
type SyncFilesOptions = Simplify<Pick<GlobalOptions, 'allFilePaths' | 'basePath' | 'fetchAdapter' | 'fileAdapter' | 'manageFilenames' | 'maxFilenameLength' | 'obsidianVault' | 'strictLineBreaks' | 'syncMediaAssets'> & SyncNotesOptions>;
declare const defaultSyncFilesOptions: SyncFilesOptions;
type SyncedFile = Simplify<SyncedNote & {
  filePath: string | undefined;
  filePathOriginal: string | undefined;
}>;
type SyncFilesResult = Simplify<Omit<SyncNotesResult, 'synced'> & {
  synced: SyncedFile[];
}>;
/**
 * Sync a list of local yanki files to Anki.
 *
 * Wraps the syncNotes function to handle file I/O.
 *
 * Most importantly, it updates the note IDs in the frontmatter of the local
 * files.
 *
 * @param allLocalFilePaths Array of paths to the local markdown files
 *
 * @returns The synced files (with new IDs where applicable), plus some stats
 *   about the sync
 * @throws {Error} If syncing fails or file operations encounter an error.
 */
declare function syncFiles(allLocalFilePaths: string[], options?: PartialDeep<SyncFilesOptions>): Promise<SyncFilesResult>;
declare function formatSyncFilesResult(result: SyncFilesResult, verbose?: boolean): string;
//#endregion
//#region src/lib/parse/parse.d.ts
type GetNoteFromMarkdownOptions = Pick<GlobalOptions, 'allFilePaths' | 'basePath' | 'cwd' | 'fetchAdapter' | 'fileAdapter' | 'namespace' | 'obsidianVault' | 'resolveUrls' | 'strictLineBreaks' | 'syncMediaAssets'> & {
  /**
   * Needed for the public API, but optional for more efficient use internally
   * when the namespace is already validated.
   */
  namespaceValidationAndSanitization: boolean;
};
declare const defaultGetNoteFromMarkdownOptions: GetNoteFromMarkdownOptions;
declare function getNoteFromMarkdown(markdown: string, options?: Partial<GetNoteFromMarkdownOptions>): Promise<YankiNote>;
//#endregion
//#region src/lib/utilities/url.d.ts
declare function urlToHostAndPort(url: string): undefined | {
  host: string;
  port: number;
};
declare function hostAndPortToUrl(host: string, port: number): string;
//#endregion
export { type CleanOptions, type CleanResult, type FetchAdapter, type FileAdapter, type GetNoteFromMarkdownOptions, type GetStyleOptions, type ListOptions, type RenameFilesOptions, type RenameFilesResult, type SetStyleOptions, type SetStyleResult, type SyncFilesOptions, type SyncFilesResult, type SyncNotesOptions, type SyncNotesResult, type YankiNote, cleanNotes, defaultCleanOptions, defaultGetNoteFromMarkdownOptions, defaultGetStyleOptions, defaultListOptions, defaultRenameFilesOptions, defaultSetStyleOptions, defaultSyncFilesOptions, defaultSyncNotesOptions, formatCleanResult, formatListResult, formatSetStyleResult, formatSyncFilesResult, getNoteFromMarkdown, getStyle, hostAndPortToUrl, listNotes, renameFiles, setStyle, syncFiles, syncNotes, urlToHostAndPort };