/* Code to handle Backup/Restore functionality */

const BACKUP_STORAGEFILE_DIR = "storage-files";

function bangleDownload() {
  var zip = new JSZip();
  Progress.show({title:"Scanning...",sticky:true});
  var normalFiles, storageFiles;
  console.log("Listing normal files...");
  return Comms.reset()
  .then(() => Comms.showMessage("Backing up..."))
  .then(() => Comms.listFiles({sf:false}))
  .then(f => {
    normalFiles = f;
    console.log(" - "+f.join(","));
    console.log("Listing StorageFiles...");
    return Comms.listFiles({sf:true});
  }).then(f => {
    storageFiles = f;
    console.log(" - "+f.join(","));
    var fileCount = normalFiles.length + storageFiles.length;
    var promise = Promise.resolve();
    // Normal files
    normalFiles.forEach((filename,n) => {
      if (filename==".firmware") {
        console.log("Ignoring .firmware file");
        return;
      }
      promise = promise.then(() => {
        Progress.hide({sticky: true});
        var percent = n/fileCount;
        Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent+(1/fileCount),percent:0});
        return Comms.readFile(filename).then(data => zip.file(filename,data));
      });
    });
    // Storage files
    if (storageFiles.length) {
      var zipStorageFiles = zip.folder(BACKUP_STORAGEFILE_DIR);
      storageFiles.forEach((filename,n) => {
        promise = promise.then(() => {
          Progress.hide({sticky: true});
          var percent = (normalFiles.length+n)/fileCount;
          Progress.show({title:`Download ${filename}`,sticky:true,min:percent,max:percent+(1/fileCount),percent:0});
          return Comms.readStorageFile(filename).then(data => zipStorageFiles.file(filename,data));
        });
      });
    }
    return promise;
  }).then(() => {
    return Comms.showMessage(Const.MESSAGE_RELOAD);
  }).then(() => {
    return zip.generateAsync({type:"binarystring"});
  }).then(content => {
    Progress.hide({ sticky: true });
    showToast('Backup complete!', 'success');
    if (typeof Android !== "undefined" && typeof Android.saveFile === 'function') {
      // Recent Gadgetbridge version that provides the saveFile interface
      Android.saveFile("Banglejs backup.zip", "application/zip", btoa(content));
    } else {
      Espruino.Core.Utils.fileSaveDialog(content, "Banglejs backup.zip");
    }
  }).catch(err => {
    Progress.hide({ sticky: true });
    showToast('Backup failed, ' + err, 'error');
  });
}

function bangleUpload() {
  return new Promise(resolve =>
    Espruino.Core.Utils.fileOpenDialog({
        id:"backup",
        type:"arraybuffer",
        mimeType:".zip,application/zip"}, function(data) {
      if (data===undefined) return;
      var zip = new JSZip();
      var cmds = "";
      return zip.loadAsync(data).then(function(zip) {
        return showPrompt("Restore from ZIP","Are you sure? This will overwrite existing apps");
      }).then(()=>{
        Progress.show({title:`Reading ZIP`});
        var promise = Promise.resolve();
        zip.forEach(function (path, file){
          console.log("path");
          promise = promise
          .then(() => file.async("string"))
          .then(data => {
            console.log("decoded", path);
            if (data.length==0) { // https://github.com/espruino/BangleApps/issues/1593
              console.log("Can't restore files of length 0, ignoring "+path);
            } else if (path.startsWith(BACKUP_STORAGEFILE_DIR)) {
              path = path.substr(BACKUP_STORAGEFILE_DIR.length+1);
              cmds += AppInfo.getStorageFileUploadCommands(path, data)+"\n";
            } else if (!path.includes("/")) {
              cmds += AppInfo.getFileUploadCommands(path, data)+"\n";
            } else console.log("Ignoring "+path);
          });
        });
        return promise;
      })
      .then(()=>new Promise(resolve => {
        showPrompt("Erase Storage","Erase Storage? If restoring a complete backup you should erase storage, but in some cases you may want to upload files from a ZIP while keeping your Bangle's existing data.").then(()=>resolve(true), ()=>resolve(false));
      }))
      .then(eraseStorage => {
        if (eraseStorage) {
          Progress.hide({sticky:true});
          Progress.show({title:`Erasing...`});
          return Comms.removeAllApps();
        }})
      .then(() => {
        Progress.hide({sticky:true});
        Progress.show({title:`Restoring...`, sticky:true});
        return Comms.showMessage(`Restoring...`); })
      .then(() => Comms.uploadCommandList(cmds, 0, cmds.length))
      .then(() => getInstalledApps(true))
      .then(() => Comms.showMessage(Const.MESSAGE_RELOAD))
      .then(() => {
        Progress.hide({sticky:true});
        showToast('Restore complete!', 'success');
        resolve();
      })
      .catch(err => {
        Progress.hide({sticky:true});
        showToast('Restore failed, ' + err, 'error');
        resolve();
      });
  }));
}

window.addEventListener('load', (event) => {
  document.getElementById("downloadallapps").addEventListener("click",event=>{
    startOperation({name:"Backup Apps"}, () => bangleDownload());
  });
  document.getElementById("uploadallapps").addEventListener("click",event=>{
    startOperation({name:"Restore Apps"}, () => bangleUpload());
  });
});
