// [DEPRECATED] 2026-02-10: This file is a legacy reference from Aether V2/V4. 
// Do NOT import this into the SvelteKit frontend. 
// The active native logic resides in the 'aether_app_native_electron' repository.

// @ts-nocheck
'use strict';
/* This should only contain functions that can not be pulled easily into Svelte */
/*
Exported functions in use:
* load_config()
* check_hash_file_cache()
* download_hash_file_to_cache()
* open_hash_file_to_temp()
* open_local_file()
* kill_processes()
* run_osascript()
* run_cmd()
* get_device_info

Local functions in use:
* open_local_file()
*/

const child_process = require('child_process');
const crypto = require('crypto');
const fs = require('fs');
const fs_promises = require('node:fs/promises');
const os = require('os');
const path = require('path');
const { ipcRenderer } = require('electron');

// import psList from 'ps-list';
// const ps_list = require('ps-list');

let home_directory = require('os').homedir();
console.log('Home: ' + home_directory);

let tmp_directory = require('os').tmpdir();
console.log('Temporary: ' + tmp_directory);

let app_root_path = path.join(home_directory, 'OSIT/native_app'); // macOS default

let config = null;

let default_osit_sync_app_root_relative_path =
    'OSIT/Speaker Ready System/Admin Share/Custom Applications'; // Mainly for macOS laptops
let default_osit_sync_app_root_path = path.join(
    home_directory,
    default_osit_sync_app_root_relative_path
); // macOS default
let default_osit_sync_native_app_relative_path =
    'OSIT/Speaker Ready System/Admin Share/Custom Applications/osit_binaries/osit_aether.current.app'; // Mainly for macOS laptops
let default_native_app_relative_path = 'OSIT/native_app/osit_aether.app'; // Mainly for macOS laptops
let default_current_native_app_relative_path = 'OSIT/native_app/osit_aether.current.app'; // Mainly for macOS laptops
let test_native_app_relative_path = 'OSIT/native_app/osit_aether.remote.app'; // Mainly for macOS laptops

// exports.check_for_native_app_update = function () {
//     console.log('*** Aether App Native export: check_for_native_app_update() ***');
//
//     let config_directory = null;
//
//     if (os.platform == 'darwin') {
//         config_directory = path.join(home_directory, 'OSIT/native_app');
//         console.log('macOS config directory: '+config_directory);
//
//         let electron_app_path = path.join(home_directory, default_native_app_relative_path);
//         let test_stats = fs.statSync(electron_app_path);
//         console.log(test_stats);
//
//         if (test_stats.ctimeMs < 1684182140759) {
//             console.log(`This may be an old version!`);
//         }
//     } else if (os.platform == 'linux') {
//         config_directory = path.join(home_directory, '.config/OSIT');
//         console.log('Linux config directory: '+config_directory);
//     } else {
//         console.log('Unknown OS... Is this Windows?');
//         return false;
//     }
//
// }

exports.load_init_config = function () {
    console.log('*** Aether App Native export: load_init_config() ***');

    let cwd = process.cwd();
    console.log(`CWD: ${cwd}`);

    try {
        if (cwd == '/') {
            cwd = home_directory;
        }
        let directory_list = fs.readdirSync(cwd);
        console.log('CWD Contents:', directory_list);
    } catch (err) {
        console.error(err);
    }

    // let home_directory = require('os').homedir();
    // console.log('Home: '+home_directory);

    // let tmp_directory = require('os').tmpdir();
    // console.log('Temporary: '+tmp_directory);

    // let config = null;
    let config_directory = null;
    // let default_config_path = path.join(process.cwd(),'ae_native_app_config.current.json');
    let default_config_path = 'ae_native_app_config.current.json';
    console.log(`Default Config File (path): ${default_config_path}`);
    let config_path = null;

    // Set the config path for macOS or Linux
    if (os.platform == 'darwin') {
        // config_directory = path.join(home_directory, 'Library/Application Support/OSIT');
        config_directory = path.join(home_directory, 'OSIT/native_app');
        console.log('macOS config directory: ' + config_directory);

        let electron_app_path = path.join(home_directory, default_native_app_relative_path);
        let test_stats = fs.statSync(electron_app_path);
        console.log(test_stats);
    } else if (os.platform == 'linux') {
        config_directory = path.join(home_directory, '.config/OSIT');
        console.log('Linux config directory: ' + config_directory);
    }

    // Look for the config file and copy the default if not found.
    if (fs.existsSync(config_directory)) {
        console.log('Config directory found: ' + config_directory);
    } else {
        fs.mkdirSync(config_directory);
        console.log('Config directory created: ' + config_directory);

        //default_config_path = path.join(process.cwd(),'ae_native_app_config.current.json');
        // config_path = path.join(config_directory, 'ae_native_app_config.json');
        // fs.copyFileSync(default_config_path, config_path);
        // console.log('Default config file copied: '+config_directory);
    }

    config_path = path.join(config_directory, 'ae_native_app_config.json');

    // Attempt to open the config file. The preferred location is based on the OS's config directory.
    if (fs.existsSync(config_path)) {
        console.log(`Config file (ae_native_app_config.json) found under ${config_directory}`);
    } else if (!fs.existsSync(config_path) && fs.existsSync(default_config_path)) {
        fs.copyFileSync(default_config_path, config_path);
        console.log('Default config file copied: ' + config_directory);

        // config = JSON.parse(fs.readFileSync(config_path));
        // console.log('Config file read.');
    } else if (fs.existsSync(path.join(cwd, 'ae_native_app_config.json'))) {
        //fs.copyFileSync(default_config_path, config_path);
        //console.log('Default config file copied: '+config_directory);

        console.log(
            `Config file (config.json) not found under ${config_directory}. Using config in CWD. ${cwd}`
        );
        config_path = path.join(cwd, 'ae_native_app_config.json');

        console.log(
            `Config file (config.json) not found under ${config_directory}. Using config in CWD. ${cwd}`
        );
        let found_config_path = path.join(cwd, 'ae_native_app_config.json');

        fs.copyFileSync(found_config_path, config_path);
        console.log(`Found config file copied: ${config_directory}`);
    } else if (fs.existsSync(path.join(cwd, 'ae_native_app_config.current.json'))) {
        console.log(
            `Config file (config.json) not found under ${config_directory} or CWD. Using default config in CWD. ${cwd}`
        );
        default_config_path = path.join(cwd, 'ae_native_app_config.current.json');

        fs.copyFileSync(default_config_path, config_path);
        console.log(`Default config file copied: ${config_directory}`);
    } else {
        console.log('Can not find a config file.');

        return false;
    }

    let local_config = JSON.parse(fs.readFileSync(config_path));
    console.log('Config file read.', local_config);
    config = local_config;

    // Do some quick clean up.

    config.home_directory = home_directory; // From the OS platform
    config.tmp_directory = tmp_directory; // From the OS platform

    config.app_root_path = config.app_root_path.replace('[home]', home_directory);
    config.app_root_path = config.app_root_path.replace('[tmp]', tmp_directory);
    console.log(`App Root Path: ${config.app_root_path}`);

    config.local_file_cache_path = config.local_file_cache_path.replace('[home]', home_directory);
    config.local_file_cache_path = config.local_file_cache_path.replace('[tmp]', tmp_directory);
    console.log(`Local File Cache Path: ${config.local_file_cache_path}`);
    if (fs.existsSync(config.local_file_cache_path)) {
    } else {
        fs.mkdirSync(config.local_file_cache_path);
        console.log(`Host file cache directory created: ${config.local_file_cache_path}`);
    }

    config.host_file_temp_path = config.host_file_temp_path.replace('[home]', home_directory);
    config.host_file_temp_path = config.host_file_temp_path.replace('[tmp]', tmp_directory);
    console.log(`Host file temp path: ${config.host_file_temp_path}`);
    if (fs.existsSync(config.host_file_temp_path)) {
    } else {
        fs.mkdirSync(config.host_file_temp_path);
        console.log(`Host file temp directory created: ${config.host_file_temp_path}`);
    }

    // NOTE: This is not ideal...
    if (!config.account_id) {
        if (config.event_id == 'pjrcghqwert' || config.event_id == 'nmBfuGFeR0k') {
            config.account_id = '_XY7DXtc9MY';
        } else if (config.event_id == 'r8c-rr-I4-52') {
            // CMSC
            config.account_id = '8Gfxbxr19Nw';
        } else if (config.event_id == 'NeC-hm-MF-Q3') {
            // LCI
            config.account_id = 'xFP7AhU8Zlc';
        } else if (config.event_id == 'Y7v-Zg-fe-gu') {
            // NCSD
            config.account_id = 'FrodrLD7B4w';
        } else if (config.event_id == '9jW-Db-SF-wt') {
            // AAPOR
            config.account_id = 'j5EBhRDqPuw';
        } else if (config.event_id == 'zJP-Ld-A7-I4') {
            // BGH
            config.account_id = 'GpLf_bnywCs';
        } else {
            console.log(
                'WARNING WARNING WARNING: The account ID could not be guessed. Using the default of 1. <<< WARNING'
            );
            config.account_id = '_XY7DXtc9MY';
        }
    }

    let import_config_to_ipc_result = ipcRenderer.invoke('import_config', config).then((result) => {
        console.log('IPC import config finished');
        // console.log(result);
        return result; // Result should be "true"
    });

    //console.log(config);
    return config;
};

exports.load_full_config = function (init_config) {
    console.log('*** Aether App Native export: load_config() ***');

    console.log('Init config.', init_config);
    // config = init_config;

    config = get_url_cfg(init_config).then((cfg) => {
        console.log('URL config file downloaded.', cfg);

        let new_config = init_config;

        // Update with remote device config settings from API.
        new_config.account_id = cfg.account_id_random;
        new_config.event_id = cfg.event_id_random;
        new_config.event_device_id = cfg.event_device_id;
        new_config.event_location_id = cfg.event_location_id;
        new_config.event_session_id = cfg.event_session_id;

        new_config.check_event_device_loop_period = cfg.check_event_device_loop_period;
        new_config.check_event_location_loop_period = cfg.check_event_location_loop_period;
        new_config.check_event_loop_period = cfg.check_event_loop_period;
        new_config.check_event_session_loop_period = cfg.check_event_session_loop_period;

        new_config.record_audio = cfg.record_audio;
        new_config.record_video = cfg.record_video;
        new_config.recording_path = cfg.recording_path;
        new_config.recording_path = new_config.recording_path.replace('[home]', home_directory);
        new_config.recording_path = new_config.recording_path.replace('[tmp]', home_directory);

        new_config.home_directory = home_directory; // From the OS platform
        new_config.tmp_directory = tmp_directory; // From the OS platform

        new_config.app_root_path = new_config.app_root_path.replace('[home]', home_directory);
        new_config.app_root_path = new_config.app_root_path.replace('[tmp]', tmp_directory);
        console.log(`App Root Path: ${new_config.app_root_path}`);

        new_config.local_file_cache_path = new_config.local_file_cache_path.replace(
            '[home]',
            home_directory
        );
        new_config.local_file_cache_path = new_config.local_file_cache_path.replace(
            '[tmp]',
            tmp_directory
        );
        console.log(`Local File Cache Path: ${new_config.local_file_cache_path}`);
        if (fs.existsSync(new_config.local_file_cache_path)) {
        } else {
            fs.mkdirSync(new_config.local_file_cache_path);
            console.log(`Host file cache directory created: ${new_config.local_file_cache_path}`);
        }

        new_config.host_file_temp_path = new_config.host_file_temp_path.replace(
            '[home]',
            home_directory
        );
        new_config.host_file_temp_path = new_config.host_file_temp_path.replace(
            '[tmp]',
            tmp_directory
        );
        console.log(`Host file temp path: ${new_config.host_file_temp_path}`);
        if (fs.existsSync(new_config.host_file_temp_path)) {
        } else {
            fs.mkdirSync(new_config.host_file_temp_path);
            console.log(`Host file temp directory created: ${new_config.host_file_temp_path}`);
        }

        let import_config_to_ipc_result = ipcRenderer
            .invoke('import_config', new_config)
            .then((result) => {
                console.log('IPC import config finished');
                // console.log(result);
                return result; // Result should be "true"
            });

        return new_config;
    });

    //console.log(config);
    return config;
};

async function get_url_cfg(cfg) {
    let base_url = `${cfg.api_protocol}://${cfg.api_server}:${cfg.api_port}/${cfg.api_path}`;

    let axios_api = axios.create({
        baseURL: base_url,
        timeout: 60000 // in milliseconds; 60000 = 60 seconds
        /* other custom settings */
    });
    // axios_api.defaults.headers = cfg['headers'];

    // axios.defaults.baseURL = `${cfg.api_protocol}://${cfg.api_server}:${cfg.api_port}/${cfg.api_path}`;
    axios_api.defaults.headers.common['Access-Control-Allow-Origin'] =
        cfg.access_control_allow_origin; // '*'; // app_cfg.access_control_allow_origin;
    axios_api.defaults.headers.common['Content-Type'] = 'application/json';
    axios_api.defaults.headers.common['x-aether-api-key'] = cfg.api_secret_key;
    // axios_api.defaults.headers.common['x-account-id'] = cfg.account_id;

    let event_device_id = 'dbgMWS3KEHE';
    let endpoint = `/event/device/${event_device_id}`;

    let params = { event_device_code: 'asdf' };

    let response_data_promise = await axios_api
        .get(endpoint, {
            params: params,
            onDownloadProgress: (progressEvent) => {
                let percent_completed = Math.round(
                    (progressEvent.loaded * 100) / progressEvent.total
                );
                console.log(
                    'GET Data Timestamp:',
                    progressEvent.timeStamp,
                    'Total:',
                    progressEvent.total,
                    'Loaded:',
                    progressEvent.loaded,
                    'Percent Completed',
                    percent_completed
                );

                // temp_get_object_percent_completed = percent_completed;
            }
        })
        .then(function (response) {
            console.log(`Response: ${response}`);

            let return_data = response.data['data'];
            if (Array.isArray(return_data)) {
                console.log(`Data result is an array/list. Array length: ${return_data.length}`);
            } else {
                console.log(`Data result is a dictionary/object, not an array/list.`);
            }
            return return_data;
        })
        .catch(function (error) {
            console.log(`Base URL: ${base_url} | Endpoint: ${endpoint}`);

            console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
            if (error.response) {
                console.log(
                    `Response Status: ${error.response.status}; Status Text: ${error.response.statusText}`
                );
            } else {
                console.log('Error:', error);
            }

            if (error.response && error.response.status === 404) {
                return null; // Returning null since there were no results
            }
            return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
        });

    return response_data_promise;
}

// Check for local file
// Updated 2022-05-06
exports.check_local_file = async function ({ local_file_path, filename }) {
    console.log('*** Electron framework export: check_local_file() ***');
    // console.log('Check for local file');
    console.log(`Local File Path: ${local_file_path}; Filename: ${filename}`);

    let full_local_file_path = path.join(local_file_path, filename);
    console.log(full_local_file_path);

    if (fs.existsSync(full_local_file_path)) {
        console.log(`Local file exists: ${full_local_file_path}`);
        return true;
    } else {
        return false;
    }
};

// Check local hash file cache
// Used by Svelte Event Launcher
// NOTE: Trying to replace this with something directly in the Svelte app part. 2022-10-11
// Updated 2022-05-06
exports.check_hash_file_cache = async function ({ local_file_cache_path, hash }) {
    // console.log('*** Electron framework export: check_hash_file_cache() ***');
    // console.log('Check local hash file cache');
    console.log(
        `*** Electron framework export: check_hash_file_cache() *** Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}`
    );

    let hash_filename = `${hash}.file`;

    let subdirectory = hash_filename.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, subdirectory);
    if (fs.existsSync(subdirectory_path)) {
    } else {
        console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
        return false;
    }

    let hash_file_cache_path = path.join(subdirectory_path, hash_filename);
    // console.log(hash_file_cache_path);

    if (fs.existsSync(hash_file_cache_path)) {
        // console.log(`Hashed file exists in cache: ${hash_file_cache_path}`);
        return true;
    } else {
        console.log(`Hashed file not found in cache: ${hash_file_cache_path}`);
        return false;
    }
};

// Check local hash file cache
// Used by Svelte Event Launcher
// Updated 2022-10-12
exports.check_hash_file_cache_v2 = async function ({
    local_file_cache_path,
    hash,
    verify_hash = false
}) {
    console.log('*** Aether App Native export: check_hash_file_cache_v2() ***');
    console.log(`Local File Cache Path: ${local_file_cache_path}; Hash: ${hash}`);

    if (fs.existsSync(local_file_cache_path)) {
    } else {
        // This should not happen. The directory needs to be created.
        console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
        return false;
    }

    let hash_filename = `${hash}.file`;

    let hash_subdirectory = hash_filename.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);

    if (fs.existsSync(subdirectory_path)) {
    } else {
        // This should not happen. The subdirectory needs to be created.
        console.log(`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`);
        return false;
    }

    let full_cached_hash_path = path.join(subdirectory_path, hash_filename);

    if (fs.existsSync(full_cached_hash_path)) {
        // console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);

        if (verify_hash) {
            const file_buffer = fs.readFileSync(full_cached_hash_path);
            const file_hash_sha256 = crypto.createHash('sha256');
            file_hash_sha256.update(file_buffer);

            const file_hash_sha256_check = file_hash_sha256.digest('hex');
            if (file_hash_sha256_check == hash) {
                console.log('File hash match', file_hash_sha256_check);
            } else {
                // This should only happen if the file is actively being downloaded or it is corrupt.
                console.log('File hash does not match', file_hash_sha256_check);
                return false;
            }
        }
        return true;
    } else {
        console.log(`Hashed file not found in cache: ${full_cached_hash_path}`);
        return null;
    }
};

// Download hash file to cache
// Used by Svelte Event Launcher
// Updated 2022-05-06
exports.download_hash_file_to_cache = async function ({
    api_base_url,
    local_file_cache_path,
    event_file_id = null,
    hash = null
}) {
    // console.log('*** Electron framework export: download_hash_file_to_cache() ***');
    // console.log('Download hash file to cache');
    console.log(
        `*** Electron framework export: download_hash_file_to_cache() *** Base URL: ${api_base_url}; Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
    );

    let endpoint = `/event/file/${event_file_id}/download`;

    let hash_filename = `${hash}.file`;

    let subdirectory = hash_filename.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, subdirectory);
    if (fs.existsSync(subdirectory_path)) {
    } else {
        fs.mkdirSync(subdirectory_path);
        console.log(`Subdirectory directory created: ${subdirectory_path}`);
    }

    let hash_file_cache_path = path.join(subdirectory_path, hash_filename);
    if (fs.existsSync(hash_file_cache_path)) {
        if (check_hash) {
            const file_buffer = fs.readFileSync(hash_file_cache_path);
            const file_hash_sha256 = crypto.createHash('sha256');
            file_hash_sha256.update(file_buffer);

            const file_hash_sha256_check = file_hash_sha256.digest('hex');
            S;
            if (file_hash_sha256_check == hash) {
                console.log('File hash match', file_hash_sha256_check);
                return true;
            } else {
                // This should only happen if the file is actively being downloaded or it is corrupt.
                console.log('File hash does not match', file_hash_sha256_check);
                return false;
            }
        }
    }
    // console.log(`!!!ABOUT TO CALL DOWNLOAD FILE HANDLER!!! exports.download_hash_file_to_cache(); Base URL: ${api_base_url}`);
    let download_file_result = await ipcRenderer
        .invoke('download_file', api_base_url, endpoint, hash_file_cache_path)
        .then((result) => {
            if (result) {
                console.log('IPC download file process finished successfully');
                return true;
            } else if (result == null) {
                console.log('IPC Download Result (file not found?):', result);
                return null;
            } else {
                console.log(
                    'IPC Download Result (file being downloaded or something went wrong):',
                    result
                );
                return false;
            }
        });
    // console.log(`!!!DONE WITH DOWNLOAD FILE HANDLER!!! exports.download_hash_file_to_cache(); Base URL: ${api_base_url}`);

    return download_file_result;
};

// Download hash file to cache
// Used by Svelte Event Launcher
// Updated 2023-05-26
exports.download_hash_file_to_cache_v2 = async function ({
    api_base_url,
    api_base_url_backup,
    local_file_cache_path,
    event_file_id = null,
    hash = null,
    verify_hash = true,
    overwrite_existing = false
}) {
    console.log('*** Aether App Native export: download_hash_file_to_cache_v2() ***');
    console.log(
        `Base URL: ${api_base_url}; Base URL Backup: ${api_base_url_backup}; Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
    );

    if (fs.existsSync(local_file_cache_path)) {
    } else {
        // This should not happen. The directory needs to be created.
        console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
        return false;
    }

    let endpoint = `/event/file/${event_file_id}/download`;

    let hash_filename = `${hash}.file`;

    let hash_subdirectory = hash_filename.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);

    if (fs.existsSync(subdirectory_path)) {
    } else {
        fs.mkdirSync(subdirectory_path);
        console.log(
            `Hashed file subdirectory directory created in cache directory: ${subdirectory_path}`
        );
    }

    let full_cached_hash_path = path.join(subdirectory_path, hash_filename);

    if (fs.existsSync(full_cached_hash_path)) {
        console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);

        if (verify_hash) {
            const file_buffer = fs.readFileSync(full_cached_hash_path);
            const file_hash_sha256 = crypto.createHash('sha256');
            file_hash_sha256.update(file_buffer);

            const file_hash_sha256_check = file_hash_sha256.digest('hex');
            if (file_hash_sha256_check == hash) {
                // console.log('File hash match', file_hash_sha256_check);
                if (overwrite_existing) {
                    console.log(
                        'Going to overwrite the existing file even though the hash matches.'
                    );
                } else {
                    return true;
                }
            } else {
                // This should only happen if the file is actively being copied or it is corrupt.
                console.log('File hash does not match', file_hash_sha256_check);
                if (overwrite_existing) {
                    console.log(
                        'Going to overwrite the existing file because the hash does not match.'
                    );
                } else {
                    return false;
                }
            }
        }
    }

    const tmp_full_save_path = full_cached_hash_path + '.tmp';

    if (fs.existsSync(tmp_full_save_path)) {
        console.log(`A temp download file was found! ${tmp_full_save_path}`);

        let stats = null;
        try {
            stats = fs.statSync(tmp_full_save_path);

            // console.log(`File Accessed Last: ${stats.atime}`); // File data last changed (actual contents)
            console.log(`File Data Last Modified: ${stats.mtime}`); // File data last changed (actual contents)
            console.log(`File Metadata Last Modified: ${stats.ctime}`); // File metadata last changed (filename, permissions, etc)
        } catch (error) {
            console.log(error);
        }

        let current_datetime = new Date();
        let offset_minutes = 3; // In minutes. 5 minutes of no changes to the file content seems reasonable? Trying with 3 minutes 2022-10-12
        let offset_datetime = new Date(current_datetime.getTime() - offset_minutes * 60000);

        // console.log(`Times: ${current_datetime} ${offset_datetime} | File ${stats.mtime}`);
        if (stats.mtime < offset_datetime) {
            // console.log(`Marking as expired temp file based on modified datetime. Expire after: ${offset_minutes} minutes`);
            // overwrite_existing = true;
        } else {
            console.log(
                `Temp download file has not expired yet. Expire after: ${offset_minutes} minutes`
            );
            // return false;
            return 'tmp';
        }
    }

    console.log(`Trying IPC API download from: ${api_base_url}`);
    let download_file_result = await ipcRenderer
        .invoke(
            'download_file',
            api_base_url,
            endpoint,
            full_cached_hash_path,
            hash,
            verify_hash,
            overwrite_existing
        )
        .then(async (result) => {
            if (result) {
                console.log(`IPC API download file process finished successfully: ${hash}`);
                return true;
            } else if (result == null) {
                console.log(`IPC API download result (file not found?):`, result);
                return null;
            } else if (result === 'in_progress') {
                console.log(`IPC API primary download IN PROGRESS: ${hash}`);
                // return false; // Should return result instead???
                return result;
            } else if (result === 'tmp') {
                console.log(`IPC API primary download FOUND TMP: ${hash}`);
                // return false; // Should return result instead???
                return result;
            } else {
                console.log(
                    `IPC API download result (file being downloaded or something went wrong): ${hash}`,
                    result
                );
                return false;

                // if (api_base_url_backup) {
                //     console.log(`Download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`);
                //     let download_backup_file_result = await ipcRenderer.invoke('download_file', api_base_url_backup, endpoint, full_cached_hash_path, hash, verify_hash, overwrite_existing).then((result_backup) => {
                //         if (result_backup) {
                //             console.log('IPC download file (from backup) process finished successfully');
                //             return true;
                //         } else if (result_backup == null) {
                //             console.log('IPC Download Result (from backup) (file not found?):', result_backup);
                //             return null;
                //         } else {
                //             console.log('IPC Download Result (from backup) (file being downloaded or something went wrong):', result_backup);
                //             return false;
                //         }
                //     });
                // } else {
                //     return false;
                // }
            }
            return true;
            // });
        })
        .then(async (result) => {
            if (result === false) {
                console.log(`IPC API primary download FAILED!`); // Trying again with backup API server. API Backup: ${api_base_url_backup}`);
                if (api_base_url_backup) {
                    console.log(
                        `IPC API primary download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`
                    );
                    console.log(`Trying IPC API backup download from: ${api_base_url_backup}`);
                    let download_backup_file_result = await ipcRenderer
                        .invoke(
                            'download_file',
                            api_base_url_backup,
                            endpoint,
                            full_cached_hash_path,
                            hash,
                            verify_hash,
                            overwrite_existing
                        )
                        .then((result_backup) => {
                            if (result_backup) {
                                console.log(
                                    `IPC API backup download file (from backup) process finished successfully: ${hash}`
                                );
                                return true;
                            } else if (result_backup == null) {
                                console.log(
                                    'IPC API backup download result (file not found?):',
                                    result_backup
                                );
                                return null;
                            } else {
                                console.log(
                                    `IPC API backup download result (file being downloaded or something went wrong): ${hash}`,
                                    result_backup
                                );
                                return false;
                            }
                        });
                    return download_backup_file_result;
                } else {
                    console.log(
                        `IPC Download FAILED! No backup API server passed. Returning false.`
                    );
                    return false;
                }
            } else if (result === 'in_progress') {
                console.log(`IPC API primary download IN PROGRESS: ${hash}`);
                return false; // Should return result instead???
            } else if (result === 'tmp') {
                console.log(`IPC API primary download FOUND TMP: ${hash}`);
                return false; // Should return result instead???
            } else {
                return result;
            }
        });

    // if (download_file_result === false) {
    //     console.log(`Download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`)
    //     download_file_result = await ipcRenderer.invoke('download_file', api_base_url_backup, endpoint, full_cached_hash_path, hash, verify_hash, overwrite_existing).then((result) => {
    //         if (result) {
    //             console.log('IPC download file (from backup) process finished successfully');
    //             return true;
    //         } else if (result == null) {
    //             console.log('IPC Download Result (from backup) (file not found?):', result);
    //             return null;
    //         } else {
    //             console.log('IPC Download Result (from backup) (file being downloaded or something went wrong):', result);
    //             return false;
    //         }
    //     });
    // }

    return download_file_result;
};

// Open cached hash file after copying to temp directory
// Used by Svelte Event Launcher
// NOTE: Trying to replace this with something directly in the Svelte app part. 2022-10-11
// Updated 2022-05-06
exports.open_hash_file_to_temp = async function ({
    local_file_cache_path,
    hash,
    host_file_temp_path,
    filename
}) {
    console.log('*** Electron framework export: open_hash_file_to_temp() ***');
    // console.log('Open cached hash file after copying to temp directory');
    console.log(
        `Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
    );

    let subdirectory = hash.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, subdirectory);
    if (fs.existsSync(subdirectory_path)) {
    } else {
        console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
        return false;
    }

    let open_hash_file_to_temp_result = await ipcRenderer
        .invoke('open_hash_file_to_temp', subdirectory_path, hash, host_file_temp_path, filename)
        .then((result) => {
            console.log('IPC open hash file to temp finished');
            console.log(result);
            return true;
        });

    // let result = await ipcRenderer.send('open_local_file', local_file_cache_path, hash, host_file_temp_path, filename);
    // console.log(result);

    console.log(open_hash_file_to_temp_result);
    console.log('End: open_hash_file_to_temp()');
    if (open_hash_file_to_temp_result) {
        console.log('File opened successfully');
        return true;
    } else {
        console.log('File was not opened successfully');
        return false;
    }
};

// Open cached hash file after copying to temp directory
// Used by Svelte Event Launcher
// Updated 2022-10-12
exports.open_hash_file_to_temp_v2 = async function ({
    local_file_cache_path,
    hash,
    host_file_temp_path,
    filename,
    verify_hash = true
}) {
    console.log('*** Aether App Native export: open_hash_file_to_temp_v2() ***');
    console.log(
        `Local File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Local File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
    );

    // console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');

    if (fs.existsSync(local_file_cache_path)) {
    } else {
        // This should not happen. The directory needs to be created.
        console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
        return false;
    }

    let hash_filename = `${hash}.file`;

    let hash_subdirectory = hash_filename.substring(0, 2);
    let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);

    if (fs.existsSync(subdirectory_path)) {
    } else {
        // This should not happen. The subdirectory needs to be created.
        console.log(`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`);
        return false;
    }

    let full_cached_hash_path = path.join(subdirectory_path, hash_filename);

    if (fs.existsSync(full_cached_hash_path)) {
        console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);

        if (verify_hash) {
            const file_buffer = fs.readFileSync(full_cached_hash_path);
            const file_hash_sha256 = crypto.createHash('sha256');
            file_hash_sha256.update(file_buffer);

            const file_hash_sha256_check = file_hash_sha256.digest('hex');
            if (file_hash_sha256_check == hash) {
                // console.log('File hash match', file_hash_sha256_check);
            } else {
                // This should only happen if the file is actively being downloaded or it is corrupt.
                console.log('File hash does not match', file_hash_sha256_check);
                return false;
            }
        }
    } else {
        console.log(`Hashed file not found in cache: ${full_cached_hash_path}`);
        return null;
    }

    let local_file_cache_path_w_sub = subdirectory_path; // I need to go back and clean up the variable names related file directory and file paths.
    // NOTE: Setting check_hash to false since by default it was checked above.
    let open_hash_file_to_temp_result = await ipcRenderer
        .invoke(
            'open_hash_file_to_temp',
            local_file_cache_path_w_sub,
            hash,
            host_file_temp_path,
            filename,
            (verify_hash = false)
        )
        .then((result) => {
            console.log('IPC open hash file to temp finished');
            if (result) {
                console.log('Local hash file was opened from temp directory.');
                return result;
            } else {
                console.log(
                    'Local hash file was not opened from the temp directory. Something went wrong.'
                );
                console.log(result);
                return false;
            }
        });

    // let result = await ipcRenderer.send('open_local_file', local_file_cache_path, hash, host_file_temp_path, filename);
    // console.log(result);

    // console.log(open_hash_file_to_temp_result);
    // console.log('End: open_hash_file_to_temp()');
    // if (open_hash_file_to_temp_result) {
    //     console.log('File opened successfully');
    //     return true;
    // } else {
    //     console.log('File was not opened successfully');
    //     return false;
    // }

    // let open_hash_file_to_temp_result = await ipcRenderer.invoke('open_hash_file_to_temp', subdirectory_path, hash, host_file_temp_path, filename).then((result) => {
    //     console.log('IPC open hash file to temp finished');
    //     if (result) {
    //         console.log('Local hash file was opened from temp directory.');
    //         return result;
    //     } else {
    //         console.log('Local hash file was not opened from the temp directory. Something went wrong.');
    //         console.log(result);
    //         return false;
    //     }
    // })

    return open_hash_file_to_temp_result;
};

// Open local file
// Used by Svelte Event Launcher
// NOTE: Trying to replace this with something directly in the Svelte app part. 2022-10-11
// Updated 2022-03-10
exports.open_local_file = async function ({ local_file_path, filename }) {
    console.log('*** Electron framework export: open_local_file() ***');
    // console.log('Open local file');
    console.log(`Local File Path: ${local_file_path}; Filename: ${filename}`);

    // let full_local_file_path = path.join(local_file_path, filename);
    // console.log(full_local_file_path);

    // if (fs.existsSync(full_local_file_path)) {
    //     console.log(`Local file exists: ${full_local_file_path}`);
    //     // return true;
    // } else {
    //     return false;
    // }

    let open_local_file_result = await ipcRenderer
        .invoke('open_local_file', local_file_path, filename)
        .then((result) => {
            console.log('IPC open local file finished');
            console.log(result);
            return true;
        });

    console.log(open_local_file_result);
    console.log('End: open_local_file()');
    if (open_local_file_result) {
        console.log('File opened successfully');
        return true;
    } else {
        console.log('File was not opened successfully');
        return false;
    }
};

// // Check local file cache and download from server if needed.
// // Updated 2022-03-09
// // exports.check_file_cache = async function ({local_file_cache_path, event_file_id, hash}) {
// exports.check_file_cache = async function ({api_base_url, local_file_cache_path, event_file_id, hash}) {
//     console.log('*** Electron framework export: check_file_cache() ***');
//     // console.log('Check local file cache and download from server if needed.');
//     console.log(`Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`);

//     // NOTE: event_file_id is the event_file.id_random or event_file.event_file_id_random
//     let hash_filename = hash+'.file';

//     let save_path = path.join(local_file_cache_path, hash_filename);
//     console.log(save_path);

//     if (fs.existsSync(save_path)) {
//         console.log('Hashed file cache already exists: '+save_path);
//         return true;
//     } else {
//         console.log('Hashed file not found in local cache. Downloading file: '+save_path);
//         let endpoint = `/event/file/${event_file_id}/download`;
//         let result = await ipcRenderer.send('download_file', api_base_url, endpoint, save_path); // Must download file using main node.js thread.
//         console.log(result);

//         return new Promise((resolve, reject) => {
//             ipcRenderer.once('download_file_reply', function(event, response){
//                 console.log(response);
//                 return response;
//             })
//             resolve(true);
//         });

//         // await ipcRenderer.once('download_file_reply', function(event, response){
//         //     console.log(response);
//         //     return response;
//         // });

//         // result.then(function (response) {
//         //     console.log('Downloaded!!!???');
//         //     return true;
//         // }).catch(function (error: any) {
//         //     console.log(error);
//         //     return false;
//         // });

//         // return result;

//         // console.log(result);
//         // if (result) {
//         //     return true;
//         // } else {
//         //     return false;
//         // }
//     }
// }

// Check local file cache and download from server if needed. Must use IPC to Main to download file. Set a Promise to wait for download_file_reply.
// Updated 2022-03-09
async function check_file_cache({ api_base_url, local_file_cache_path, event_file_id, hash }) {
    console.log('*** Electron framework: check_file_cache() ***');
    // console.log('Check local file cache and download from server if needed.');
    console.log(
        `Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
    );

    // NOTE: event_file_id is the event_file.id_random or event_file.event_file_id_random
    let hash_filename = hash + '.file';

    let save_path = path.join(local_file_cache_path, hash_filename);
    console.log(save_path);

    if (fs.existsSync(save_path)) {
        console.log('Hashed file cache already exists: ' + save_path);
        return true;
    } else {
        console.log('Hashed file not found in local cache. Downloading file: ' + save_path);
        let endpoint = `/event/file/${event_file_id}/download`;
        let result = await ipcRenderer.send('download_file', api_base_url, endpoint, save_path); // Must download file using main node.js thread.
        console.log(result);

        return new Promise((resolve, reject) => {
            ipcRenderer.once('download_file_reply', function (event, response) {
                console.log(response);
                return response;
            });
            resolve(true);
        });

        // await ipcRenderer.once('download_file_reply', function(event, response){
        //     console.log(response);
        //     return response;
        // });

        // result.then(function (response) {
        //     console.log('Downloaded!!!???');
        //     return true;
        // }).catch(function (error: any) {
        //     console.log(error);
        //     return false;
        // });

        // return result;

        // console.log(result);
        // if (result) {
        //     return true;
        // } else {
        //     return false;
        // }
    }
}

// IPC to Main: Open local file cache if available. Copy to temp directory with given filename first.
// Updated 2022-03-09
async function open_local_file({ local_file_cache_path, hash, host_file_temp_path, filename }) {
    console.log('*** Electron framework: open_local_file() ***');
    // console.log('Open local file cache if available. Copy to temp directory with given filename first.');
    console.log(
        `Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
    );

    console.log(local_file_cache_path);
    console.log(hash);
    console.log(filename);

    let result = await ipcRenderer.send(
        'open_local_file',
        local_file_cache_path,
        hash,
        host_file_temp_path,
        filename
    );
    console.log(result);

    return true;
}

// No longer needed? Not referenced as of 2022-10-11
exports.check_file_cache_and_open_local_file = async function ({
    local_file_cache_path,
    event_file_id,
    hash,
    host_file_temp_path,
    filename
}) {
    console.log('*** Electron framework: check_file_cache_and_open_local_file() ***');
    console.log(
        'Checking the local file cache against the remote server and then opening the local file.'
    );

    let check_file_cache_result = check_file_cache({
        local_file_cache_path: local_file_cache_path,
        event_file_id: event_file_id,
        hash: hash
    });
    console.log(check_file_cache_result);

    if (check_file_cache_result) {
        let open_local_file_result = open_local_file({
            local_file_cache_path: local_file_cache_path,
            hash: hash,
            host_file_temp_path: host_file_temp_path,
            filename: filename
        });
        console.log(open_local_file_result);

        return open_local_file_result;
    }

    ipcRenderer.once('download_file_reply', function (event, response) {
        console.log(response);

        let open_local_file_result = open_local_file({
            local_file_cache_path: local_file_cache_path,
            hash: hash,
            host_file_temp_path: host_file_temp_path,
            filename: filename
        });
        console.log(open_local_file_result);

        return open_local_file_result;
    });
};

// Kill processes
// Signals: HUP (hang up), INT (interrupt), QUIT (quit), ABRT (abort), KILL (non-catchable, non-ignoraable kill), ALRMn (alarm clock), TERM (default; software termination signal)
// Updated 2022-05-07
exports.kill_processes = async function ({
    process_name = null,
    process_id = null,
    signal = null
}) {
    console.log('*** Electron framework export: kill_processes() ***');
    console.log(process_name); // process_name or grep pattern

    let cmd = '';
    if (os.platform == 'darwin') {
        if (signal == 'HUP') {
            cmd = `killall -HUP '${process_name}'`;
        } else if (signal == 'INT') {
            cmd = `killall -INT '${process_name}'`;
        } else if (signal == 'QUIT') {
            cmd = `killall -QUIT '${process_name}'`;
        } else if (signal == 'ABRT') {
            cmd = `killall -ABRT '${process_name}'`;
        } else if (signal == 'KILL') {
            cmd = `killall -KILL '${process_name}'`;
        } else if (signal == 'ALRM') {
            cmd = `killall -ALRM '${process_name}'`;
        } else if (signal == 'TERM') {
            cmd = `killall -TERM '${process_name}'`;
        } else if (process_id && signal == 'HUP') {
            cmd = `killall -HUP ${process_id}`;
        } else if (process_id && signal == 'INT') {
            cmd = `killall -INT ${process_id}`;
        } else if (process_id && signal == 'QUIT') {
            cmd = `killall -QUIT ${process_id}`;
        } else if (process_id && signal == 'ABRT') {
            cmd = `killall -ABRT ${process_id}`;
        } else if (process_id && signal == 'KILL') {
            cmd = `killall -KILL ${process_id}`;
        } else if (process_id && signal == 'ALRM') {
            cmd = `killall -ALRM ${process_id}`;
        } else if (process_id && signal == 'TERM') {
            cmd = `killall -TERM ${process_id}`;
        } else {
            // cmd = `osascript -e 'quit app "${process_name}" saving no'`;
            cmd = `osascript -e 'quit application "${process_name}" saving no'`;
        }
    } else {
        cmd = `pkill ${process_name}`;
    }

    child_process.exec(cmd, (err, stdout, stdin) => {
        // if (err) throw err;
        if (err) console.log(err);
        console.log(stdout);
    });
    console.log(`Killed processes matching ${process_name}`);

    if (os.platform == 'darwin') {
        if (process_name == 'Parallels:Acrobat Reader') {
            // Regular expression: (Parallels).*(Acrobat Reader)
            // This will find any process with Parallels and Acrobat Reader in the name
            cmd = `pkill -i -f '(Parallels).*(Acrobat Reader)'`;

            child_process.exec(cmd, (err, stdout, stdin) => {
                if (err) throw err;
                console.log(stdout);
            });
            console.log('Killed Parallels Acrobat Reader process');
        }

        if (process_name == 'Parallels:PowerPoint') {
            // Regular expression: (Parallels).*(PowerPoint)
            // This will find any process with Parallels and PowerPoint in the name
            cmd = `pkill -i -f '(Parallels).*(PowerPoint)'`;

            child_process.exec(cmd, (err, stdout, stdin) => {
                if (err) throw err;
                console.log(stdout);
            });
            console.log('Killed Parallels PowerPoint process');
        }
    }

    // let signal = 'SIGTERM'; // 'SIGTERM', 'SIGINT', 'SIGHUP'
    // process.kill(pid, signal);
    // process.kill(pid, 0); // Special case test if process exists

    return true;
};

// Run raw osascript
// Updated 2022-05-07
exports.run_osascript = async function ({
    cmd = null,
    interactive = false,
    language = null,
    flags = 'h',
    program_file = null
}) {
    console.log('*** Electron framework export: run_osascript() ***');
    console.log(cmd);

    if (os.platform == 'darwin') {
    } else {
        console.log('Not available for this platform. macOS (darwin) only.');
        return false;
    }

    let osascript_str = '';

    if (Array.isArray(cmd)) {
        console.log('List of cmd strings');
        let cmds_str = '';
        for (let i = 0; i < cmd.length; i++) {
            cmds_str += `-e '${cmd[i]}'`;
        }
        osascript_str = `osascript ${cmds_str}`;
    } else if (typeof cmd === 'string') {
        console.log('Single cmd string');
        osascript_str = `osascript -e '${cmd}'`;
    } else {
        return false;
    }

    if (language) {
        console.log(`Language: ${language}`);
        osascript_str = `${osascript_str} -l ${language}`;
    }

    if (flags) {
        console.log(`Flags: ${flags}`);
        osascript_str = `${osascript_str} -s ${flags}`;
    }

    console.log(`OSA Script String: ${osascript_str}`);
    child_process.exec(osascript_str, (err, stdout, stdin) => {
        if (err) throw err;
        console.log(stdout);
        console.log(stdin);
    });

    console.log('Finished');
    return true;
};

// Run raw command
// Updated 2026-01-26
exports.run_cmd = async function ({
    cmd = null,
    return_stdout = null,
    return_stdin = null,
    sync = null
}) {
    console.log('*** Electron framework export: run_cmd() ***');

    // Resolve placeholders in the command string
    let cleaned_cmd = cmd;
    if (cmd && typeof cmd === 'string') {
        cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
    }

    console.log(`Command String: ${cleaned_cmd}`);

    let result;

    if (!sync) {
        result = child_process.exec(cleaned_cmd, (err, stdout, stdin) => {
            // if (err) throw err;
            if (err) {
                console.log('Error:', err);
                return false;
            }

            console.log('stdout:', stdout);
            // console.log('stdin:', stdin);

            if (return_stdout) {
                console.log('Finished and returning stdout');
                return stdout;
            } else {
                console.log('Finished and returning true');
                return true;
            }
        });
    } else {
        result = child_process.execSync(cleaned_cmd, (err, stdout, stdin) => {
            // if (err) throw err;
            if (err) {
                console.log('Error:', err);
                return false;
            }

            console.log('stdout:', stdout);
            // console.log('stdin:', stdin);

            if (return_stdout) {
                console.log('Finished and returning stdout');
                return stdout;
            } else {
                console.log('Finished and returning true');
                return true;
            }
        });
    }

    console.log('Result:', result);
    return result;
};

// Run raw command sync
// Updated 2026-01-26
exports.run_cmd_sync = function ({ cmd = null, return_stdout = null, return_stdin = null }) {
    console.log('*** Electron framework export: run_cmd_sync() ***');

    // Resolve placeholders in the command string
    let cleaned_cmd = cmd;
    if (cmd && typeof cmd === 'string') {
        cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
    }

    console.log(`Command String: ${cleaned_cmd}`);

    let stdout;

    try {
        stdout = child_process.execSync(cleaned_cmd, { encoding: 'utf8' });
        console.log('Std Out:', stdout);
    } catch (err) {
        console.error('Error:', err);
        return false;
    }

    if (return_stdout) {
        console.log('Finished and returning stdout');
        return stdout;
    } else {
        console.log('Finished and returning true');
        return true;
    }
};

// Run raw command
// Updated 2026-01-26
exports.get_device_info = async function () {
    console.log('*** Electron framework export: get_device_info() ***');

    // https://nodejs.org/api/os.html

    let data = {};
    data['arch'] = os.arch();
    data['hostname'] = os.hostname();
    data['cpus'] = os.cpus();
    data['freemem'] = os.freemem();
    data['totalmem'] = os.totalmem();
    data['loadavg'] = os.loadavg();
    data['networkInterfaces'] = os.networkInterfaces();
    data['platform'] = os.platform();
    data['release'] = os.release();
    data['uptime'] = os.uptime();
    data['version'] = os.version();
    
    // Add directory info for placeholder resolution in UI
    data['home_directory'] = home_directory;
    data['tmp_directory'] = tmp_directory;

    console.log(data);
    return data;
};

/**
 * Atomic Copy-and-Launch (Phase 2/5)
 * Moves a file from the hashed cache to the operational temp directory
 * and triggers the system launcher.
 */
exports.launch_from_cache = async function ({ 
    cache_root, 
    hash, 
    temp_root, 
    filename, 
    hash_prefix_length = 2 
}) {
    console.log('*** Aether App Native export: launch_from_cache() ***');
    
    // 1. Resolve Path Placeholders (using global regex)
    const clean_cache_root = cache_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
    const clean_temp_root = temp_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
    
    const hash_filename = `${hash}.file`;
    const prefix = hash.substring(0, hash_prefix_length);
    const source_path = path.join(clean_cache_root, prefix, hash_filename);
    const dest_path = path.join(clean_temp_root, filename);

    console.log(`Source: ${source_path}`);
    console.log(`Dest: ${dest_path}`);

    try {
        // 2. Ensure temp directory exists
        if (!fs.existsSync(clean_temp_root)) {
            fs.mkdirSync(clean_temp_root, { recursive: true });
        }

        // 3. Verify Source
        if (!fs.existsSync(source_path)) {
            throw new Error(`Source file not found in cache: ${source_path}`);
        }

        // 4. Perform atomic copy
        fs.copyFileSync(source_path, dest_path);
        console.log('File copied to temp successfully.');

        // 5. Trigger Specialized Launcher (if presentation)
        const ext = path.extname(filename).toLowerCase().replace('.', '');
        const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);

        if (is_pres) {
            return await exports.launch_presentation({ 
                path: dest_path, 
                app: ext === 'key' ? 'keynote' : 'default' 
            });
        }

        // 6. Default Fallback
        return await ipcRenderer.invoke('open_local_file', '', dest_path);

    } catch (err) {
        console.error('Launch Error:', err);
        return { success: false, error: err.message };
    }
};

/**
 * Specialized Presentation Launcher (Phase 5)
 * Handles platform-specific application selection (LibreOffice on Linux, 
 * PowerPoint/Keynote on macOS).
 * Updated 2026-01-26
 */
exports.launch_presentation = async function ({ 
    path: raw_path, 
    app = 'default',
    os_platform = 'auto'
}) {
    console.log('*** Aether App Native export: launch_presentation() ***');
    
    // Resolve placeholders if they exist in the incoming path (using global regex)
    let cleaned_path = raw_path
        .replace(/\[home\]/g, home_directory)
        .replace(/\[tmp\]/g, tmp_directory);

    console.log(`Raw Path: ${raw_path}; Cleaned Path: ${cleaned_path}; App: ${app}; OS: ${os_platform}`);

    // 1. Detect OS
    let platform = os_platform;
    if (platform === 'auto') {
        platform = os.platform();
    }

    // 2. Handle Linux (LibreOffice Testing)
    if (platform === 'linux') {
        console.log(`Native: Launching LibreOffice on Linux for path: ${cleaned_path}`);
        const cmd = `libreoffice --impress "${cleaned_path}"`;
        
        return new Promise((resolve) => {
            child_process.exec(cmd, (err, stdout, stderr) => {
                if (err) {
                    console.error('LibreOffice Launch Error:', err);
                    resolve({ success: false, error: err.message });
                } else {
                    resolve({ success: true, stdout, stderr });
                }
            });
        });
    }

    // 3. Handle macOS (Production)
    if (platform === 'darwin') {
        if (app === 'keynote') {
            const script = `tell application "Keynote" to open POSIX file "${cleaned_path}"`;
            return exports.run_osascript({ cmd: script });
        }
        
        // Default to shell open
        return ipcRenderer.invoke('open_local_file', '', cleaned_path);
    }

    // 4. Default Fallback (Windows/Others)
    return ipcRenderer.invoke('open_local_file', '', cleaned_path);
};

// For loading JS file
function loadJS() {
    // Gives -1 when the given input is not in the string
    // i.e this file has not been added

    if (filesAdded.indexOf('script.js') !== -1) return;

    // Head tag
    var head = document.getElementsByTagName('head')[0];

    // Creating script element
    var script = document.createElement('script');
    script.src = 'script.js';
    script.type = 'text/javascript';

    // Adding script element
    head.append(script);

    // Adding the name of the file to keep record
    filesAdded += ' script.js';
}

// To load CSS file
function loadCSS() {
    if (filesAdded.indexOf('styles.css') !== -1) return;

    var head = document.getElementsByTagName('head')[0];

    // Creating link element
    var style = document.createElement('link');
    style.href = 'styles.css';
    style.type = 'text/css';
    style.rel = 'stylesheet';
    head.append(style);

    // Adding the name of the file to keep record
    filesAdded += ' styles.css';
}

exports.check_and_get_updated_native_app_config = function ({
    file_path = 'device_configs/ae_native_app_config.default.json',
    overwrite = false
}) {
    console.log('*** Aether App Native export: check_and_get_updated_native_app_config() ***');

    if (os.platform == 'darwin') {
        let default_osit_sync_app_config_path = path.join(
            default_osit_sync_app_root_path,
            file_path
        );

        let default_app_config_path = path.join(app_root_path, 'ae_native_app_config.default.json');
        console.log('macOS app root and config directory: ' + default_app_config_path);

        fs.copyFileSync(default_osit_sync_app_config_path, default_app_config_path);

        if (overwrite) {
            console.log('Overwriting the current active config file...');
            let active_app_config_path = path.join(app_root_path, 'ae_native_app_config.json');
            console.log('macOS app root and config directory: ' + active_app_config_path);

            fs.copyFileSync(default_osit_sync_app_config_path, active_app_config_path);
        }
    } else if (os.platform == 'linux') {
        app_root_path = path.join(home_directory, '.config/OSIT');
        console.log('Linux config directory: ' + app_root_path);
        return false;
    } else {
        console.log('Unknown OS... Is this Windows?');
        return false;
    }

    return true;
};
