"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runningAsWindowsService = void 0;
exports.getDiskSpaceSync = getDiskSpaceSync;
exports.bashEscape = bashEscape;
exports.cmdEscape = cmdEscape;
exports.getDiskSpace = getDiskSpace;
exports.getDiskSpaces = getDiskSpaces;
exports.getDrives = getDrives;
exports.runCmd = runCmd;
exports.reg = reg;
const path_1 = require("path");
const fs_1 = require("fs");
const child_process_1 = require("child_process");
const misc_1 = require("./misc");
const csv_1 = __importDefault(require("@gregoranders/csv"));
const node_process_1 = require("node:process");
const util_1 = require("util");
const const_1 = require("./const");
const promises_1 = require("node:fs/promises");
const DF_TIMEOUT = 2000;
function getDiskSpaceSync(path) {
    while (path && !(0, misc_1.isWindowsDrive)(path) && !(0, fs_1.existsSync)(path))
        path = (0, path_1.dirname)(path);
    const res = (0, fs_1.statfsSync)(path);
    return { free: res.bavail * res.bsize, total: res.blocks * res.bsize, name: path };
}
function bashEscape(par) {
    return `'${par.replaceAll(/(["'$`\\])/g, "\\$1")}'`;
}
function cmdEscape(par) {
    return `"${par.replaceAll('"', '\\"')}"`;
}
async function getDiskSpace(path) {
    while (path && !(0, misc_1.isWindowsDrive)(path) && !await (0, misc_1.exists)(path))
        path = (0, path_1.dirname)(path);
    const res = await (0, promises_1.statfs)(path);
    return { free: res.bavail * res.bsize, total: res.blocks * res.bsize, name: path };
}
async function getDiskSpaces() {
    if (const_1.IS_WINDOWS) {
        const drives = await getDrives();
        return (0, misc_1.onlyTruthy)(await (0, misc_1.promiseBestEffort)(drives.map(getDiskSpace)));
    }
    return parseDfResult(await (0, util_1.promisify)(child_process_1.exec)(`df -k`, { timeout: DF_TIMEOUT }).then(x => x.stdout, e => e));
}
function parseDfResult(result) {
    if (result instanceof Error) {
        const { status } = result;
        throw status === 1 ? Error('miss') : status === 127 ? Error('unsupported') : result;
    }
    const out = result.split('\n');
    if (!out.shift()?.startsWith('Filesystem'))
        throw Error('unsupported');
    return (0, misc_1.onlyTruthy)(out.map(one => {
        const bits = one.split(/\s+/);
        if (bits[0] === 'tempfs')
            return;
        const name = bits.pop() || '';
        if (/^\/(dev|sys|run|System\/Volumes\/(VM|Preboot|Update|xarts|iSCPreboot|Hardware))\b/.test(name))
            return;
        const [used = 0, free = 0] = bits.map(x => Number(x) * 1024).slice(2);
        const total = used + free;
        return total && { free, total, name };
    }));
}
async function getDrives() {
    const res = await runCmd('fsutil fsinfo drives'); // example output: `Drives: C:\ D:\ Z:\`
    return res.trim().replaceAll('\\', '').split(' ').slice(1);
}
// execute win32 shell commands
async function runCmd(cmd, args = [], options = {}) {
    const line = `@chcp 65001 >nul & cmd /c ${cmd} ${args.map(x => x.includes(' ') ? `"${x}"` : x).join(' ')}`;
    const { stdout, stderr } = await (0, util_1.promisify)(child_process_1.exec)(line, { encoding: 'utf-8', ...options });
    return (stderr || stdout).replace(/\r/g, '');
}
// returns pid-to-name object
async function getWindowsServicePids() {
    const res = await runCmd('tasklist /svc /fo csv');
    const parsed = new csv_1.default().parse(res);
    const no = parsed?.[1]?.[2];
    return Object.fromEntries(parsed.slice(2).filter(x => x[2] !== no).map(x => [x[1], x[2]]));
}
exports.runningAsWindowsService = const_1.IS_WINDOWS && getWindowsServicePids().then(x => {
    const ret = x[node_process_1.pid] || x[node_process_1.ppid];
    if (ret)
        console.log("Running as service", ret);
    return ret;
}, e => {
    console.log("Couldn't determine if we are running as a service");
    console.debug(e);
});
function reg(...pars) {
    return (0, util_1.promisify)(child_process_1.execFile)('reg', pars).then(x => x.stdout);
}
