import { BrowserWindow, DownloadItem, Event, SaveDialogOptions, WebContents } from "electron";

//#region src/DownloadData.d.ts
interface RestoreDownloadData {
  /**
   * Download id
   */
  id: string;
  url: string;
  /**
   * The path and filename where the download will be saved.
   */
  fileSaveAsPath: string;
  urlChain: string[];
  mimeType: string;
  /**
   * The ETag of the download, if available.
   * This is used to resume downloads.
   */
  eTag: string;
  receivedBytes: number;
  totalBytes: number;
  startTime: number;
  percentCompleted: number;
  /**
   * If persistOnAppClose is true, this is the path where the download
   * is persisted to. This is used to restore the download later.
   */
  persistedFilePath?: string;
}
interface DownloadDataConfig {
  /**
   * Download id
   */
  id?: string;
}
/**
 * Contains the data for a download.
 */
declare class DownloadData {
  /**
   * Generated id for the download
   */
  id: string;
  /**
   * The Electron.DownloadItem. Use this to grab the filename, path, etc.
   * @see https://www.electronjs.org/docs/latest/api/download-item
   */
  item: DownloadItem;
  /**
   * The Electron.WebContents
   * @see https://www.electronjs.org/docs/latest/api/web-contents
   */
  webContents: WebContents;
  /**
   * The Electron.Event
   * @see https://www.electronjs.org/docs/latest/api/event
   */
  event: Event;
  /**
   * The name of the file that is being saved to the user's computer.
   * Recommended over Item.getFilename() as it may be inaccurate when using the save as dialog.
   */
  resolvedFilename: string;
  /**
   * If true, the download was cancelled from the save as dialog. This flag
   * will also be true if the download was cancelled by the application when
   * using the save as dialog.
   */
  cancelledFromSaveAsDialog?: boolean;
  /**
   * The percentage of the download that has been completed
   */
  percentCompleted: number;
  /**
   * The download rate in bytes per second.
   */
  downloadRateBytesPerSecond: number;
  /**
   * The estimated time remaining in seconds.
   */
  estimatedTimeRemainingSeconds: number;
  /**
   * If the download was interrupted, the state in which it was interrupted from
   */
  interruptedVia?: "in-progress" | "completed";
  /**
   * If defined, this is the path where the download is persisted to.
   */
  persistedFilePath?: string;
  constructor(config?: DownloadDataConfig);
  /**
   * Returns data necessary for restoring a download
   */
  getRestoreDownloadData(): RestoreDownloadData;
  isDownloadInProgress(): boolean;
  isDownloadCompleted(): boolean;
  isDownloadCancelled(): boolean;
  isDownloadInterrupted(): boolean;
  isDownloadResumable(): boolean;
  isDownloadPaused(): boolean;
}
//#endregion
//#region src/types.d.ts
/**
 * The download has started
 */
type DownloadStartedFn = (data: DownloadData) => Promise<void> | void;
/**
 * There is progress on the download
 */
type DownloadProgressFn = (data: DownloadData) => Promise<void> | void;
/**
 * The download has been cancelled
 */
type DownloadCancelledFn = (data: DownloadData) => Promise<void> | void;
/**
 * The download has completed
 */
type DownloadCompletedFn = (data: DownloadData) => Promise<void> | void;
/**
 * The download was interrupted
 */
type DownloadInterruptedFn = (data: DownloadData) => Promise<void> | void;
/**
 * The download has been persisted for later restoration
 */
type DownloadPersistedFn = (data: DownloadData, restoreDownloadData: RestoreDownloadData) => Promise<void> | void;
/**
 * The download has failed
 */
type ErrorFn = (error: Error, data?: DownloadData) => Promise<void> | void;
/**
 * Function for logging internal debug messages
 */
type DebugLoggerFn = (message: string) => void;
interface DownloadManagerConstructorParams {
  /**
   * If defined, will log out internal debug messages. Useful for
   * troubleshooting downloads. Does not log out progress due to
   * how frequent it can be.
   */
  debugLogger?: DebugLoggerFn;
}
interface DownloadManagerCallbacks {
  /**
   * When the download has started. When using a "save as" dialog,
   * this will be called after the user has selected a location.
   *
   * This will always be called first before the progress and completed events.
   */
  onDownloadStarted?: DownloadStartedFn;
  /**
   * When there is a progress update on a download. Note: This
   * may be skipped entirely in some cases, where the download
   * completes immediately. In that case, onDownloadCompleted
   * will be called instead.
   */
  onDownloadProgress?: DownloadProgressFn;
  /**
   * When the download has completed
   */
  onDownloadCompleted?: DownloadCompletedFn;
  /**
   * When the download has been cancelled. Also called if the user cancels
   * from the save as dialog.
   */
  onDownloadCancelled?: DownloadCancelledFn;
  /**
   * When the download has been interrupted. This could be due to a bad
   * connection, the server going down, etc.
   */
  onDownloadInterrupted?: DownloadInterruptedFn;
  /**
   * When the download has been persisted for later restoration.
   */
  onDownloadPersisted?: DownloadPersistedFn;
  /**
   * When an error has been encountered.
   * Note: The signature is (error, <maybe some data>).
   */
  onError?: ErrorFn;
}
interface RestoreDownloadConfig {
  /**
   * The Electron.App instance
   */
  app: Electron.App;
  /**
   * The Electron.BrowserWindow instance
   */
  window: BrowserWindow;
  /**
   * Data required for resuming the download
   */
  restoreData: RestoreDownloadData;
  /**
   * The callbacks to define to listen for download events
   */
  callbacks: DownloadManagerCallbacks;
  /**
   * Electron.DownloadURLOptions to pass to the downloadURL method
   *
   * @see https://www.electronjs.org/docs/latest/api/session#sesdownloadurlurl-options
   */
  downloadURLOptions?: Electron.DownloadURLOptions;
}
interface DownloadConfig {
  /**
   * The Electron.App instance. Required if persistOnAppClose is enabled.
   */
  app?: Electron.App;
  /**
   * The Electron.BrowserWindow instance
   */
  window: BrowserWindow;
  /**
   * The URL to download
   */
  url: string;
  /**
   * The callbacks to define to listen for download events
   */
  callbacks: DownloadManagerCallbacks;
  /**
   * Electron.DownloadURLOptions to pass to the downloadURL method
   *
   * @see https://www.electronjs.org/docs/latest/api/session#sesdownloadurlurl-options
   */
  downloadURLOptions?: Electron.DownloadURLOptions;
  /**
   * If defined, will show a save dialog when the user
   * downloads a file.
   *
   * @see https://www.electronjs.org/docs/latest/api/dialog#dialogshowsavedialogbrowserwindow-options
   */
  saveDialogOptions?: SaveDialogOptions;
  /**
   * The filename to save the file as. If not defined, the filename
   * from the server will be used.
   *
   * Only applies if saveDialogOptions is not defined.
   */
  saveAsFilename?: string;
  /**
   * The directory to save the file to. Must be an absolute path.
   * @default The user's downloads directory
   */
  directory?: string;
  /**
   * If true, will overwrite the file if it already exists
   * @default false
   */
  overwrite?: boolean;
  /**
   * Options for persisting a partial download when the application closes for use with restoring it later.
   */
  persistOnAppClose?: boolean;
}
interface IElectronDownloadManager {
  /**
   * Starts a download. If saveDialogOptions has been defined in the config,
   * the saveAs dialog will show up first.
   *
   * Returns the id of the download.
   *
   * This *must* be called with `await` or unintended behavior may occur.
   */
  download(params: DownloadConfig): Promise<string>;
  /**
   * Cancels a download
   */
  cancelDownload(id: string): void;
  /**
   * Pauses a download and returns the data necessary to restore it later
   */
  pauseDownload(id: string): RestoreDownloadData | undefined;
  /**
   * Resumes a download
   */
  resumeDownload(id: string): void;
  /**
   * Returns the number of active downloads
   */
  getActiveDownloadCount(): number;
  /**
   * Returns the data for a download
   */
  getDownloadData(id: string): DownloadData | undefined;
  /**
   * Restores a download that is not registered in the download manager.
   * If it is already registered, calls resumeDownload() instead.
   *
   * Returns the id of the restored download.
   */
  restoreDownload(params: RestoreDownloadConfig): Promise<string>;
}
//#endregion
//#region src/CallbackDispatcher.d.ts
/**
 * Wraps around the callbacks to handle errors and logging
 */
declare class CallbackDispatcher {
  protected logger: DebugLoggerFn;
  callbacks: DownloadManagerCallbacks;
  downloadDataId: string;
  constructor(downloadDataId: string, callbacks: DownloadManagerCallbacks, logger: (message: string) => void);
  protected log(message: string): void;
  onDownloadStarted(downloadData: DownloadData): Promise<void>;
  onDownloadCompleted(downloadData: DownloadData): Promise<void>;
  onDownloadProgress(downloadData: DownloadData): Promise<void>;
  onDownloadCancelled(downloadData: DownloadData): Promise<void>;
  onDownloadInterrupted(downloadData: DownloadData): Promise<void>;
  onDownloadPersisted(downloadData: DownloadData): Promise<void>;
  handleError(error: Error, downloadData?: DownloadData): void;
}
//#endregion
//#region src/DownloadInitiator.d.ts
interface DownloadInitiatorConstructorParams {
  /**
   * The id for the download. If not provided, a random id will be generated.
   */
  id?: string;
  /**
   * A debug logger function to log messages.
   * If not provided, no logging will occur.
   */
  debugLogger?: (message: string) => void;
  /**
   * Called when the download is cleaned up.
   * This is called after the download has completed or been cancelled.
   * @param id The download data
   */
  onCleanup?: (id: DownloadData) => void;
  /**
   * Called when the download is initialized.
   * This is called before any download events are fired.
   * @param id The download data
   */
  onDownloadInit?: (id: DownloadData) => void;
  /**
   * The user callbacks to define to listen for download events
   */
  callbacks: DownloadManagerCallbacks;
}
interface WillOnDownloadParams {
  /**
   * If defined, will show a save dialog when the user
   * downloads a file.
   *
   * @see https://www.electronjs.org/docs/latest/api/dialog#dialogshowsavedialogbrowserwindow-options
   */
  saveDialogOptions?: SaveDialogOptions;
  /**
   * The filename to save the file as. If not defined, the filename
   * from the server will be used.
   *
   * Only applies if saveDialogOptions is not defined.
   */
  saveAsFilename?: string;
  /**
   * The directory to save the file to. Must be an absolute path.
   * @default The user's downloads directory
   */
  directory?: string;
  /**
   * If true, will overwrite the file if it already exists
   * @default false
   */
  overwrite?: boolean;
  /**
   * Data for restoring a download.
   */
  restoreData?: RestoreDownloadData;
}
declare class DownloadInitiator {
  protected logger: (message: string) => void;
  /**
   * When the download is initiated
   */
  private onDownloadInit;
  /**
   * When cleanup is called
   */
  private onCleanup;
  /**
   * The callback dispatcher for handling download events back to the user
   */
  private callbackDispatcher;
  /**
   * The data for the download.
   */
  private downloadData;
  private config;
  /**
   * The handler for the DownloadItem's `updated` event.
   */
  private onUpdateHandler?;
  /**
   * The handler for the DownloadItem's `done` event.
   */
  private onDoneHandler?;
  constructor(config: DownloadInitiatorConstructorParams);
  protected log(message: string): void;
  /**
   * Returns the download id
   */
  getDownloadId(): string;
  /**
   * Returns the current download data
   */
  getDownloadData(): DownloadData;
  /**
   * Generates the handler that attaches to the session `will-download` event,
   * which will execute the workflows for handling a download.
   */
  generateOnWillDownload(downloadParams: WillOnDownloadParams): (event: Event, item: DownloadItem, webContents: WebContents) => Promise<void>;
  /**
   * Flow for handling a download that requires user interaction via a "Save as" dialog.
   */
  protected initSaveAsInteractiveDownload(): void;
  private augmentDownloadItem;
  /**
   * Flow for handling a download that doesn't require user interaction.
   */
  protected initNonInteractiveDownload(isRestoring?: boolean): Promise<void>;
  protected updateProgress(): void;
  /**
   * Generates the handler for hooking into the DownloadItem's `updated` event.
   */
  protected generateItemOnUpdated(): (_event: Event, state: "progressing" | "interrupted") => Promise<void>;
  /**
   * Generates the handler for hooking into the DownloadItem's `done` event.
   */
  protected generateItemOnDone(): (_event: Event, state: "completed" | "cancelled" | "interrupted") => Promise<void>;
  protected cleanup(): void;
  private getPersistDownloadFilename;
  /**
   * Persists the download to an alternative location.
   * This is useful for saving the download state when the app is about to close.
   * It copies the current download file to a new location with a `.download` extension.
   * If the download is already completed or cancelled, it does nothing.
   */
  persistDownload(): void;
  /**
   * Restores a download from a persisted state.
   */
  restorePersistedDownload(restoreData: RestoreDownloadData): void;
}
//#endregion
//#region src/ElectronDownloadManager.d.ts
/**
 * Enables handling downloads in Electron.
 */
declare class ElectronDownloadManager implements IElectronDownloadManager {
  protected downloadData: Record<string, DownloadData>;
  protected logger: DebugLoggerFn;
  private downloadQueue;
  constructor(params?: DownloadManagerConstructorParams);
  protected log(message: string): void;
  /**
   * Returns the current download data
   */
  getDownloadData(id: string): DownloadData;
  /**
   * Cancels a download
   */
  cancelDownload(id: string): void;
  /**
   * Pauses a download and returns the data necessary
   * to restore it later via restoreDownload() if the download exists.
   */
  pauseDownload(id: string): RestoreDownloadData | undefined;
  /**
   * Resumes a download
   */
  resumeDownload(id: string): void;
  /**
   * Returns the number of active downloads
   */
  getActiveDownloadCount(): number;
  /**
   * Restores a download that is not registered in the download manager.
   * If it is already registered, calls resumeDownload() instead.
   */
  restoreDownload(params: RestoreDownloadConfig): Promise<string>;
  /**
   * Starts a download. If saveDialogOptions has been defined in the config,
   * the saveAs dialog will show up first.
   *
   * Returns the id of the download.
   */
  download(params: DownloadConfig): Promise<string>;
  protected cleanup(data: DownloadData): void;
}
//#endregion
//#region src/ElectronDownloadManagerMock.d.ts
/**
 * Mock version of ElectronDownloadManager
 * that can be used for testing purposes
 */
declare class ElectronDownloadManagerMock implements IElectronDownloadManager {
  download(_params: DownloadConfig): Promise<string>;
  cancelDownload(_id: string): void;
  pauseDownload(_id: string): RestoreDownloadData | undefined;
  resumeDownload(_id: string): void;
  getActiveDownloadCount(): number;
  getDownloadData(id: string): DownloadData;
  restoreDownload(_params: RestoreDownloadConfig): Promise<string>;
}
//#endregion
//#region src/utils.d.ts
declare function truncateUrl(url: string): string;
declare function generateRandomId(): string;
declare function getFilenameFromMime(name: string, mime: string): string;
/**
 * Determines the initial file path for the download.
 */

//#endregion
export { CallbackDispatcher, DebugLoggerFn, DownloadCancelledFn, DownloadCompletedFn, DownloadConfig, DownloadData, DownloadDataConfig, DownloadInitiator, DownloadInterruptedFn, DownloadManagerCallbacks, DownloadManagerConstructorParams, DownloadPersistedFn, DownloadProgressFn, DownloadStartedFn, ElectronDownloadManager, ElectronDownloadManagerMock, ErrorFn, IElectronDownloadManager, RestoreDownloadConfig, RestoreDownloadData, generateRandomId, getFilenameFromMime, truncateUrl };