//////////////////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2026, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////////////////

import usePreferences from '../../preferences/static/js/store';
import { callFetch, parseApiError } from './api_instance';
import { getBrowser, toPrettySize } from './utils';

const DownloadUtils = {
  downloadViaLink: function (url, fileName) {
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  },

  downloadBlob: function (blob, fileName) {
    const urlCreator = window.URL || window.webkitURL;
    const downloadUrl = urlCreator.createObjectURL(blob);

    this.downloadViaLink(downloadUrl, fileName);
    window.URL.revokeObjectURL(downloadUrl);
  },

  downloadTextData: function (textData, fileName, fileType) {
    const respBlob = new Blob([textData], {type : fileType});
    this.downloadBlob(respBlob, fileName);
  },

  downloadBase64UrlData: function (downloadUrl, fileName) {
    this.downloadViaLink(downloadUrl, fileName);
  },

  downloadFileStream: async function (allOptions, fileName, fileType, onProgress) {
    const data = [];
    const response = await callFetch(allOptions.url, allOptions.options);
    if(!response.ok) {
      throw new Error(parseApiError(await response.json()));
    }
    if (!response.body) {
      throw new Error(response.statusText);
    }

    const reader = response.body.getReader();

    let done = false;
    let receivedLength = 0; // received bytes
    while (!done) {
      const { value, done: doneReading } = await reader.read();
      done = doneReading;
      if (value) {
        data.push(value);
        receivedLength += value.length;
        onProgress?.(toPrettySize(receivedLength, 'B', 2));
      }
    }

    const blob = new Blob(data, {type: fileType});
    this.downloadBlob(blob, fileName);
  }
};

// If we are in Electron, we will use the Electron API to download files.
if(getBrowser().name == 'Electron') {
  DownloadUtils.downloadTextData = async (textData, fileName, _fileType) =>{
    const {automatically_open_downloaded_file, prompt_for_download_location} = usePreferences.getState().getPreferencesForModule('misc');
    await window.electronUI.downloadTextData(textData, {
      defaultPath: fileName,
    }, prompt_for_download_location, automatically_open_downloaded_file);
  };

  DownloadUtils.downloadBase64UrlData = async (downloadUrl, fileName) => {
    const {automatically_open_downloaded_file, prompt_for_download_location} = usePreferences.getState().getPreferencesForModule('misc');
    await window.electronUI.downloadBase64UrlData(downloadUrl, {
      defaultPath: fileName,
    }, prompt_for_download_location, automatically_open_downloaded_file);
  };

  DownloadUtils.downloadFileStream = async (allOptions, fileName, _fileType, onProgress)=>{
    const {automatically_open_downloaded_file, prompt_for_download_location} = usePreferences.getState().getPreferencesForModule('misc');
    const filePath = await window.electronUI.getDownloadStreamPath({
      defaultPath: fileName,
    }, prompt_for_download_location);

    // If the user cancels the download, we will not proceed
    if(!filePath) {
      return;
    }

    const response = await callFetch(allOptions.url, allOptions.options);
    if(!response.ok) {
      throw new Error(parseApiError(await response.json()));
    }
    if (!response.body) {
      throw new Error(response.statusText);
    }

    const contentLength = response.headers.get('Content-Length');
    window.electronUI.downloadStreamSaveTotal(filePath, contentLength ? parseInt(contentLength, 10) : null);

    const reader = response.body.getReader();

    let done = false;
    let receivedLength = 0; // received bytes
    while (!done) {
      const { value, done: doneReading } = await reader.read();
      done = doneReading;
      if (value) {
        window.electronUI.downloadStreamSaveChunk(filePath, value);
        receivedLength += value.length;
        onProgress?.(toPrettySize(receivedLength, 'B', 2));
      }
    }
    window.electronUI.downloadStreamSaveEnd(filePath, automatically_open_downloaded_file);
  };
}

export default DownloadUtils;
