const { app, dialog, shell, net, BrowserWindow, Notification, nativeImage } = require('electron');

let win;

// to get rid of "Electron Security Warning (Insecure Content-Security-Policy)" warnings;
// using recommanded <meta http-equiv="Content-Security-Policy"> will cause Matomo to
// fail, among other problems
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';

function createWindow () {
    // Create the browser window.
    win = new BrowserWindow({ width: 800, height: 600 });

    // and load the index.html of the app. 
    win.loadFile("./dist/index.html");

    // Hide menu bar.
    win.setMenuBarVisibility(false)

    // Open the DevTools.
    // win.webContents.openDevTools();

    // Ask confirmation before closing the app.
    win.on('close', (e) => {
        e.preventDefault();
        const choice = dialog.showMessageBoxSync(
            {
              type: "question",
              buttons: [ "Ok", "Cancel"] , // "OK" and "Cancel" are automatically translated
              defaultId: 1,
              cancelId: 1,
              title: "Exit Cassiopée",
              message: "Are you sure you want to exit Cassiopée ?"
           }
        );
        if(choice == 1){
            e.preventDefault();
        } else {
            win.destroy();
        }
    });

    // Emitted when the window is closed.
    win.on('closed', () => {
        win = null;
    });

    // Try to detect updates
    lookForUpdates();
};

/**
 * Compares semver strings
 * @see https://github.com/substack/semver-compare
 */
function semverCompare(a, b) {
    var pa = a.split('.');
    var pb = b.split('.');
    for (var i = 0; i < 3; i++) {
        var na = Number(pa[i]);
        var nb = Number(pb[i]);
        if (na > nb) return 1;
        if (nb > na) return -1;
        if (!isNaN(na) && isNaN(nb)) return 1;
        if (isNaN(na) && !isNaN(nb)) return -1;
    }
    return 0;
}

// debug
function alert(text) {
    dialog.showMessageBox(null, {
        message: text,
        buttons: ['Cancel']
    });
}

/**
 * Calls the Cassiopee update server to check for available updates;
 * if so, displays a desktop notification which, if clicked, will
 * trigger the download of the latest version installer for the
 * current platform
 * 
 * Web updates system prerequisites
 * --------------------------------
 * 
 * ${URL} should point to an http-accessible directory containing:
 * 
 *  1. a file named "releases.json" with a contents of the form
 *    {
 *      "latest": "4.5.0",
 *      "4.5.0": {
 *        "darwin": "cassiopee-setup-4.5.0.dmg",
 *        "linux": "fr.irstea.cassiopee_4.5.0_amd64.deb",
 *        "win32": "Cassiopée Setup 4.5.0.exe"
 *      },
 *      "4.4.2": {
 *        "darwin": "cassiopee-setup-4.4.2.dmg",
 *        "linux": "fr.irstea.cassiopee_4.4.2_amd64.deb",
 *        "win32": "Cassiopée Setup 4.4.2.exe"
 *      }
 *    }
 * 
 *  2. all platform-dependent installer files specified in "releases.json",
 *     at the root of the directory (ex: "fr.irstea.cassiopee_4.5.0_amd64.deb")
 */
const lookForUpdates = function() {
    // Web update resources root directory
    const URL = "https://cassiopee.g-eau.fr/cassiopee-releases/";

    // detect current app version and platform
    // const version = "4.4.2"; // debug
    const version = app.getVersion();
    const platform = process.platform; // "win32", "linux" or "darwin"
    // console.log(process.arch); // "x32" or "x64"

    // fetch releases information
    const req = net.request(URL + "releases.json");
    req.setHeader("Cache-Control", "no-cache");
    req.on("response", (response) => {
        if (response.statusCode === 200) {
            response.on('data', (chunk) => {
                const data = JSON.parse(chunk);
                // compare current version to latest version
                if (data.latest && semverCompare(data.latest, version) == 1) {
                    // get download link for latest version, depending on platform
                    if (data[data.latest] && data[data.latest][platform]) {
                        const latestVersionURL = URL + data[data.latest][platform];
                        // show notification on desktop
                        if (Notification.isSupported()) {
                            // @see https://stackoverflow.com/questions/41823184/how-to-get-icon-path-image-in-electron-builder
                            let iconPath = "assets/icons/electron/icon.png";
                            if (! app.isPackaged) {
                                iconPath = "dist/" + iconPath; // marche pas !? Comment obtenir le chemin de l'icône dans app.asar ?
                            }
                            let notif = new Notification({
                                title: `Cassiopee version ${data.latest} is available`,
                                body: `The desktop distribution of Cassiopeia will no longer be updated in 2024. You are invited to use the progressive web app Cassiopée instead. Click to download update installer.`,
                                icon: nativeImage.createFromPath(iconPath) // @see https://github.com/electron/electron/issues/24221
                            });
                            notif.addListener("click", () => {
                                // ask system to open URL with default browser
                                shell.openExternal(latestVersionURL);
                            });
                            setTimeout(() => {
                                notif.show();
                            }, 2000);
                        }
                    } else {
                        console.error(`could not find download link for version ${data.latest} on platform ${platform}`);
                    }
                } // else you already have the latest version
                
            });
        } else {
            console.error("error fetching releases information");
        }
    });
    req.on("error", (err) => {
        // generally net::ERR_INTERNET_DISCONNECTED, which has no incidence
        // other than preventing available updates detection
        console.error(err);
    });
    req.end();
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
    createWindow();
    if (process.platform === 'win32') {      
        // for notifications to work on windows; see https://stackoverflow.com/a/53510850/5986614
        app.setAppUserModelId(app.getName());
    }
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {
        createWindow();
    }
});