"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const electron_1 = require("electron");
const AdminServer_1 = require("./admin/AdminServer");
const HdoController_1 = require("./HdoController");
const hdoPlugin = {
    async activate(ctx) {
        const runtimeSettings = ctx.settings.get() ?? {};
        const controller = new HdoController_1.HdoController({
            userDataDir: ctx.userDataDir,
            marketServerBaseUrl: ctx.host.serverBaseUrl ?? null,
            bundledWireGuardDir: defaultBundledWireGuardDir(),
            session: ctx.host.session,
            marketplaceDb: ctx.host.marketplaceDb,
            pluginManager: ctx.host.pluginManager,
            log: ctx.log
        });
        const admin = new AdminServer_1.HdoAdminServer(controller, {
            port: runtimeSettings.adminPort ?? 23459
        });
        admin.start();
        const presenceTimer = setInterval(() => {
            const settings = controller.getSettings();
            if (settings.anonymous?.mode === 'anonymous' && !settings.sessionUserId)
                return;
            const status = controller.wireGuardStatus();
            void controller.reportDevicePresence(status && status.active === true ? 'online' : 'offline', {
                throttleMs: 10 * 60 * 1000
            }).catch((err) => {
                ctx.log.warn('failed to report HDO presence heartbeat', {
                    error: err instanceof Error ? err.message : String(err)
                });
            });
        }, 10 * 60 * 1000);
        presenceTimer.unref?.();
        let lastWireGuardRecoveryFailureAt = 0;
        const recoveryTimers = [];
        const recoverWireGuard = (reason) => {
            if (lastWireGuardRecoveryFailureAt && Date.now() - lastWireGuardRecoveryFailureAt < 5 * 60 * 1000) {
                return;
            }
            void controller.recoverWireGuardPeer({ reason, allowPrivileged: false }).catch((err) => {
                lastWireGuardRecoveryFailureAt = Date.now();
                ctx.log.warn('failed to recover HDO WireGuard desired state', {
                    reason,
                    error: err instanceof Error ? err.message : String(err)
                });
            });
        };
        const scheduleWireGuardRecovery = (reason, delays = [2500, 12_000, 25_000]) => {
            delays.forEach((delay) => {
                const timer = setTimeout(() => recoverWireGuard(reason), delay);
                timer.unref?.();
                recoveryTimers.push(timer);
            });
        };
        scheduleWireGuardRecovery('plugin-activate', [2500, 12_000]);
        const wireGuardRecoveryTimer = setInterval(() => recoverWireGuard('interval'), 45_000);
        wireGuardRecoveryTimer.unref?.();
        const onPowerResume = () => scheduleWireGuardRecovery('power-resume');
        const onUnlockScreen = () => scheduleWireGuardRecovery('unlock-screen', [1500, 10_000, 25_000]);
        electron_1.powerMonitor.on('resume', onPowerResume);
        electron_1.powerMonitor.on('unlock-screen', onUnlockScreen);
        ctx.expose({
            onEvent: (listener) => controller.onEvent(listener),
            snapshot: () => controller.snapshot(),
            updateSettings: (patch) => controller.updateSettings(patch),
            registerDevice: (input) => controller.registerDevice(input),
            reportPluginStates: (deviceId) => controller.reportPluginStates(deviceId),
            anonymousConnect: (input) => controller.anonymousConnect(input),
            login: (input) => controller.login(input ?? {}),
            accountConnect: (input) => controller.accountConnect(input),
            prepareWireGuardPeer: (input) => controller.prepareWireGuardPeer(input),
            connectWireGuardPeer: (input) => controller.connectWireGuardPeer(input),
            applyDomainProxyFromManifest: (manifest) => controller.applyDomainProxyFromManifest(manifest),
            prepareDomainProxyFromManifest: (manifest) => controller.prepareDomainProxyFromManifest(manifest),
            recoverWireGuardPeer: (reason) => controller.recoverWireGuardPeer({ reason: reason || 'api', allowPrivileged: true }),
            repairWireGuardRoutes: () => controller.repairWireGuardRoutes(),
            installWireGuardLaunchDaemon: () => controller.installWireGuardLaunchDaemon(),
            uninstallWireGuardLaunchDaemon: (input) => controller.uninstallWireGuardLaunchDaemon(input),
            executePendingTasks: () => controller.executePendingTasks(),
            refreshManifest: (deviceId) => controller.refreshManifest(deviceId),
            refreshSubscription: (deviceId) => controller.refreshSubscription(deviceId),
            upsertNode: (input) => controller.upsertNode(input),
            upsertService: (input) => controller.upsertService(input),
            publishService: (input) => controller.publishService(input),
            upsertRateLimit: (input) => controller.upsertRateLimit(input)
        });
        ctx.log.info('hdo activated', {
            adminPort: runtimeSettings.adminPort ?? 23459,
            marketServerBaseUrl: ctx.host.serverBaseUrl ?? null
        });
        return async () => {
            clearInterval(presenceTimer);
            clearInterval(wireGuardRecoveryTimer);
            recoveryTimers.forEach((timer) => clearTimeout(timer));
            electron_1.powerMonitor.off('resume', onPowerResume);
            electron_1.powerMonitor.off('unlock-screen', onUnlockScreen);
            await controller.shutdown().catch((err) => {
                ctx.log.warn('failed to shutdown HDO WireGuard', {
                    error: err instanceof Error ? err.message : String(err)
                });
            });
            await controller.reportDevicePresence('offline').catch(() => undefined);
            await admin.stop();
        };
    }
};
exports.default = hdoPlugin;
function defaultBundledWireGuardDir() {
    const resourcesPath = process.resourcesPath ?? process.cwd();
    const packageDir = typeof __dirname === 'undefined' ? process.cwd() : __dirname;
    const candidates = [
        (0, node_path_1.join)(resourcesPath, 'qpjoy-wireguard-engine'),
        (0, node_path_1.join)(resourcesPath, 'wireguard'),
        (0, node_path_1.resolve)(packageDir, '../resources/wireguard'),
        (0, node_path_1.resolve)(process.cwd(), 'resources/qpjoy-wireguard-engine'),
        (0, node_path_1.resolve)(process.cwd(), 'resources/wireguard')
    ];
    return candidates.find((candidate) => (0, node_fs_1.existsSync)(candidate)) ?? candidates[0];
}
