import os from 'node:os';
import { join } from 'node:path';
const renderLaunchdArray = (values) => values.map(value => `    <string>${escapeXml(value)}</string>`).join('\n');
const escapeXml = (value) => value
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&apos;');
const getCurrentUserId = () => (typeof process.getuid === 'function' ? process.getuid() : 0);
const getLaunchctlDomain = (scope, userId = getCurrentUserId()) => scope === 'system' ? 'system' : `gui/${userId}`;
const getSystemdPrefix = (scope) => scope === 'system' ? [] : ['--user'];
const quoteSystemdPathValue = (value) => `"${value
    .replaceAll('\\', '\\\\')
    .replaceAll('"', '\\"')
    .replaceAll('%', '%%')}"`;
const quoteSystemdExecValue = (value) => quoteSystemdPathValue(value).replaceAll('$', '$$$$');
export const resolveServicePlatform = (platform = process.platform) => {
    if (platform === 'darwin' || platform === 'linux') {
        return platform;
    }
    throw new Error(`Unsupported service platform "${platform}".`);
};
export const getDarwinServiceName = (installId) => `io.codori.server.${installId}`;
export const getLinuxServiceName = (installId) => `codori-${installId}.service`;
export const renderLaunchdPlist = ({ serviceName, launcherPath, root, metadataDirectory }) => [
    '<?xml version="1.0" encoding="UTF-8"?>',
    '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
    '<plist version="1.0">',
    '<dict>',
    '  <key>Label</key>',
    `  <string>${escapeXml(serviceName)}</string>`,
    '  <key>ProgramArguments</key>',
    '  <array>',
    renderLaunchdArray([launcherPath]),
    '  </array>',
    '  <key>RunAtLoad</key>',
    '  <true/>',
    '  <key>KeepAlive</key>',
    '  <true/>',
    '  <key>WorkingDirectory</key>',
    `  <string>${escapeXml(root)}</string>`,
    '  <key>StandardOutPath</key>',
    `  <string>${escapeXml(join(metadataDirectory, 'service.log'))}</string>`,
    '  <key>StandardErrorPath</key>',
    `  <string>${escapeXml(join(metadataDirectory, 'service.error.log'))}</string>`,
    '</dict>',
    '</plist>'
].join('\n');
export const renderSystemdUnit = ({ serviceName, launcherPath, root }) => [
    '[Unit]',
    `Description=Codori service (${serviceName})`,
    'After=network.target',
    '',
    '[Service]',
    'Type=simple',
    `WorkingDirectory=${quoteSystemdPathValue(root)}`,
    `ExecStart=${quoteSystemdExecValue(launcherPath)}`,
    'Restart=always',
    'RestartSec=5',
    '',
    '[Install]',
    'WantedBy=default.target'
].join('\n');
export const createDarwinServiceDefinition = ({ installId, scope, launcherPath, root, metadataDirectory, homeDir = os.homedir() }) => {
    const serviceName = getDarwinServiceName(installId);
    const serviceFilePath = scope === 'system'
        ? join('/Library/LaunchDaemons', `${serviceName}.plist`)
        : join(homeDir, 'Library', 'LaunchAgents', `${serviceName}.plist`);
    return {
        serviceName,
        serviceFilePath,
        serviceFileContents: renderLaunchdPlist({
            serviceName,
            launcherPath,
            root,
            metadataDirectory
        })
    };
};
export const createLinuxServiceDefinition = ({ installId, scope, launcherPath, root, homeDir = os.homedir() }) => {
    const serviceName = getLinuxServiceName(installId);
    const serviceFilePath = scope === 'system'
        ? join('/etc/systemd/system', serviceName)
        : join(homeDir, '.config', 'systemd', 'user', serviceName);
    return {
        serviceName,
        serviceFilePath,
        serviceFileContents: renderSystemdUnit({
            serviceName,
            launcherPath,
            root
        })
    };
};
export const getDarwinInstallCommands = (definition, scope, userId = getCurrentUserId()) => {
    const domain = getLaunchctlDomain(scope, userId);
    return [
        {
            command: 'launchctl',
            args: ['bootout', domain, definition.serviceFilePath]
        },
        {
            command: 'launchctl',
            args: ['bootstrap', domain, definition.serviceFilePath]
        },
        {
            command: 'launchctl',
            args: ['enable', `${domain}/${definition.serviceName}`]
        },
        {
            command: 'launchctl',
            args: ['kickstart', '-k', `${domain}/${definition.serviceName}`]
        }
    ];
};
export const getDarwinRestartCommands = (definition, scope, userId = getCurrentUserId()) => {
    const domain = getLaunchctlDomain(scope, userId);
    return [
        {
            command: 'launchctl',
            args: ['bootout', domain, definition.serviceFilePath]
        },
        {
            command: 'launchctl',
            args: ['bootstrap', domain, definition.serviceFilePath]
        },
        {
            command: 'launchctl',
            args: ['kickstart', '-k', `${domain}/${definition.serviceName}`]
        }
    ];
};
export const getDarwinUninstallCommands = (definition, scope, userId = getCurrentUserId()) => {
    const domain = getLaunchctlDomain(scope, userId);
    return [
        {
            command: 'launchctl',
            args: ['bootout', domain, definition.serviceFilePath]
        },
        {
            command: 'launchctl',
            args: ['disable', `${domain}/${definition.serviceName}`]
        }
    ];
};
export const getLinuxInstallCommands = (definition, scope) => {
    const prefix = getSystemdPrefix(scope);
    return [
        {
            command: 'systemctl',
            args: [...prefix, 'daemon-reload']
        },
        {
            command: 'systemctl',
            args: [...prefix, 'enable', '--now', definition.serviceName]
        }
    ];
};
export const getLinuxRestartCommands = (definition, scope) => {
    const prefix = getSystemdPrefix(scope);
    return [
        {
            command: 'systemctl',
            args: [...prefix, 'daemon-reload']
        },
        {
            command: 'systemctl',
            args: [...prefix, 'restart', definition.serviceName]
        }
    ];
};
export const getLinuxUninstallCommands = (definition, scope) => {
    const prefix = getSystemdPrefix(scope);
    return [
        {
            command: 'systemctl',
            args: [...prefix, 'disable', '--now', definition.serviceName]
        },
        {
            command: 'systemctl',
            args: [...prefix, 'daemon-reload']
        }
    ];
};
