"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SystemEventsCollector = void 0;
const logger_1 = require("../logger");
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
class SystemEventsCollector {
    constructor() {
        // Start collecting from 1 hour ago on first run
        this.lastCollectTime = new Date(Date.now() - 3600000);
    }
    async collect() {
        if (process.platform === 'win32') {
            return this.collectWindows();
        }
        return this.collectLinux();
    }
    collectWindows() {
        return new Promise((resolve) => {
            const since = this.lastCollectTime.toISOString();
            const scriptContent = `
$ErrorActionPreference = 'SilentlyContinue'
$since = [DateTime]::Parse('${since}')
$events = @()

function Convert-LogonType($value) {
  switch ([string]$value) {
    '2' { 'interactive' }
    '3' { 'network' }
    '4' { 'batch' }
    '5' { 'service' }
    '7' { 'unlock' }
    '8' { 'network_cleartext' }
    '9' { 'new_credentials' }
    '10' { 'remote_interactive' }
    '11' { 'cached_interactive' }
    '12' { 'cached_remote_interactive' }
    '13' { 'cached_unlock' }
    default { if ([string]::IsNullOrWhiteSpace([string]$value)) { '' } else { [string]$value } }
  }
}

# System log - errors and warnings
try {
  $sysEvents = Get-WinEvent -FilterHashtable @{
    LogName = 'System'
    Level = 1,2,3
    StartTime = $since
  } -MaxEvents 50 -ErrorAction SilentlyContinue
  foreach ($e in $sysEvents) {
    $msgLen = if ($e.Message) { [Math]::Min(500, $e.Message.Length) } else { 0 }
    $msg = if ($e.Message -and $msgLen -gt 0) { ($e.Message -replace '[\\r\\n]+', ' ').Substring(0, $msgLen) } else { '' }
    $lvl = switch($e.Level) { 1 {'critical'} 2 {'error'} 3 {'warning'} default {'info'} }
    $un = if ($e.UserId) { $e.UserId.ToString() } else { '' }
    $events += [PSCustomObject]@{
      timestamp = $e.TimeCreated.ToString('o')
      eventType = 'system'
      source = $e.ProviderName
      eventId = $e.Id
      level = $lvl
      message = $msg
      userName = $un
      computer = $e.MachineName
    }
  }
} catch { }

# Security log - logon events
try {
  $secEvents = Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    Id = 4624,4625,4634,4647,4648,4672,4740,4771,4776
    StartTime = $since
  } -MaxEvents 50 -ErrorAction SilentlyContinue
  foreach ($e in $secEvents) {
    $xml = [xml]$e.ToXml()
    $data = @{}
    foreach ($node in $xml.Event.EventData.Data) {
      if ($node.Name) { $data[$node.Name] = [string]$node.'#text' }
    }
    $type = switch($e.Id) {
      4624 {'logon'} 4625 {'logon_failed'} 4634 {'logoff'}
      4647 {'logoff'} 4648 {'explicit_credentials'} 4672 {'special_logon'}
      4740 {'account_lockout'} 4771 {'kerberos_failed'} 4776 {'credential_validation_failed'}
      default {'security'}
    }
    $authResult = switch($e.Id) {
      4624 {'success'} 4625 {'failure'} 4634 {'logoff'}
      4647 {'logoff'} 4648 {'attempt'} 4672 {'success'}
      4740 {'lockout'} 4771 {'failure'} 4776 {'failure'}
      default {'info'}
    }
    $msgLen = if ($e.Message) { [Math]::Min(500, $e.Message.Length) } else { 0 }
    $msg = if ($e.Message -and $msgLen -gt 0) { ($e.Message -replace '[\\r\\n]+', ' ').Substring(0, $msgLen) } else { '' }
    $targetUser = [string]$data.TargetUserName
    $targetDomain = [string]$data.TargetDomainName
    $fullUser = if ($targetDomain -and $targetUser) { "$targetDomain\\$targetUser" } elseif ($targetUser) { $targetUser } else { '' }
    $ip = [string]$data.IpAddress
    if ($ip -eq '-' -or $ip -eq '::1') { $ip = '' }
    $ipPort = [string]$data.IpPort
    if ($ipPort -eq '-') { $ipPort = '' }
    $failureReason = [string]$data.FailureReason
    if (-not $failureReason) {
      $status = [string]$data.Status
      $subStatus = [string]$data.SubStatus
      if ($status -and $subStatus) { $failureReason = "$status / $subStatus" }
      elseif ($status) { $failureReason = $status }
    }
    $events += [PSCustomObject]@{
      timestamp = $e.TimeCreated.ToString('o')
      eventType = $type
      source = 'Security'
      eventId = $e.Id
      level = if ($authResult -eq 'failure' -or $authResult -eq 'lockout') { 'warning' } else { 'info' }
      message = $msg
      userName = $fullUser
      computer = $e.MachineName
      sourceIp = $ip
      sourcePort = if ($ipPort) { [int]$ipPort } else { $null }
      sourceHost = [string]$data.WorkstationName
      sessionType = Convert-LogonType $data.LogonType
      authMethod = if ($data.AuthenticationPackageName) { [string]$data.AuthenticationPackageName } else { [string]$data.LogonProcessName }
      failureReason = if ($authResult -eq 'failure' -or $authResult -eq 'lockout') { $failureReason } else { '' }
      authResult = $authResult
      targetDomain = $targetDomain
    }
  }
} catch { }

# Application log - errors
try {
  $appEvents = Get-WinEvent -FilterHashtable @{
    LogName = 'Application'
    Level = 1,2
    StartTime = $since
  } -MaxEvents 30 -ErrorAction SilentlyContinue
  foreach ($e in $appEvents) {
    $msgLen = if ($e.Message) { [Math]::Min(500, $e.Message.Length) } else { 0 }
    $msg = if ($e.Message -and $msgLen -gt 0) { ($e.Message -replace '[\\r\\n]+', ' ').Substring(0, $msgLen) } else { '' }
    $lvl3 = switch($e.Level) { 1 {'critical'} 2 {'error'} default {'warning'} }
    $un3 = if ($e.UserId) { $e.UserId.ToString() } else { '' }
    $events += [PSCustomObject]@{
      timestamp = $e.TimeCreated.ToString('o')
      eventType = 'application'
      source = $e.ProviderName
      eventId = $e.Id
      level = $lvl3
      message = $msg
      userName = $un3
      computer = $e.MachineName
    }
  }
} catch { }

if ($events.Count -gt 0) {
  $events | ConvertTo-Json -Depth 3 -Compress
} else {
  Write-Output '[]'
}
`;
            // Write script to temp file to avoid escaping issues
            const scriptPath = path.join(os.tmpdir(), 'appstats-sysevents.ps1');
            try {
                fs.writeFileSync(scriptPath, scriptContent, 'utf-8');
            }
            catch (writeErr) {
                logger_1.logger.error(`Failed to write system events script: ${writeErr.message}`);
                resolve([]);
                return;
            }
            (0, child_process_1.execFile)('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath], { timeout: 30000, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
                this.lastCollectTime = new Date();
                if (err) {
                    logger_1.logger.warn(`System events collection error: ${err.message}${stderr ? ' stderr: ' + stderr.substring(0, 200) : ''}`);
                    resolve([]);
                    return;
                }
                try {
                    const raw = stdout.trim();
                    if (!raw || raw === 'null' || raw === '') {
                        resolve([]);
                        return;
                    }
                    let parsed = JSON.parse(raw);
                    if (!Array.isArray(parsed))
                        parsed = [parsed];
                    logger_1.logger.info(`System events collected: ${parsed.length} events`);
                    resolve(parsed);
                }
                catch (parseErr) {
                    logger_1.logger.warn(`System events parse error: ${parseErr.message}, raw length: ${stdout.length}`);
                    resolve([]);
                }
            });
        });
    }
    collectLinux() {
        return new Promise((resolve) => {
            const since = this.lastCollectTime.toISOString();
            (0, child_process_1.execFile)('journalctl', ['--since', since, '--output', 'json', '--no-pager', '-n', '200'], { timeout: 15000 }, (err, stdout) => {
                this.lastCollectTime = new Date();
                if (err) {
                    resolve([]);
                    return;
                }
                try {
                    const events = stdout.trim().split('\n')
                        .filter((line) => line.trim())
                        .map((line) => {
                        const j = JSON.parse(line);
                        const source = String(j.SYSLOG_IDENTIFIER || j._COMM || '');
                        const message = String(j.MESSAGE || '');
                        const priority = parseInt(j.PRIORITY, 10);
                        const authSource = /^(sshd|sudo|su|login|gdm-password|polkitd|systemd-logind|passwd)$/i.test(source);
                        const authMessage = /(accepted|failed password|authentication failure|session opened|session closed|invalid user|pam_unix|userauth|sudo:|su:)/i.test(message);
                        if (!(Number.isFinite(priority) && priority <= 3) && !authSource && !authMessage)
                            return null;
                        const accepted = message.match(/Accepted\s+([^\s]+)\s+for\s+(?:invalid user\s+)?([^\s]+)\s+from\s+([^\s]+)(?:\s+port\s+(\d+))?/i);
                        const failed = message.match(/Failed\s+([^\s]+)\s+for\s+(invalid user\s+)?([^\s]+)\s+from\s+([^\s]+)(?:\s+port\s+(\d+))?/i);
                        const pamFailure = message.match(/authentication failure.*(?:rhost=([^\s]+))?.*user=([^\s]+)/i);
                        const sessionOpened = message.match(/session opened for user ([^\s]+)/i);
                        const sessionClosed = message.match(/session closed for user ([^\s]+)/i);
                        let authResult = '';
                        let sessionType = '';
                        let authMethod = '';
                        let sourceIp = '';
                        let sourcePort = null;
                        let failureReason = '';
                        let userName = String(j._UID || '');
                        if (accepted) {
                            authResult = 'success';
                            authMethod = accepted[1];
                            userName = accepted[2];
                            sourceIp = accepted[3];
                            sourcePort = accepted[4] ? parseInt(accepted[4], 10) : null;
                            sessionType = 'remote';
                        }
                        else if (failed) {
                            authResult = 'failure';
                            authMethod = failed[1];
                            userName = failed[3];
                            sourceIp = failed[4];
                            sourcePort = failed[5] ? parseInt(failed[5], 10) : null;
                            sessionType = 'remote';
                            failureReason = failed[2] ? 'invalid user' : 'invalid credentials';
                        }
                        else if (pamFailure) {
                            authResult = 'failure';
                            userName = pamFailure[2];
                            sourceIp = pamFailure[1] || '';
                            sessionType = 'remote';
                            failureReason = 'authentication failure';
                        }
                        else if (sessionOpened) {
                            authResult = 'success';
                            userName = sessionOpened[1];
                        }
                        else if (sessionClosed) {
                            authResult = 'logoff';
                            userName = sessionClosed[1];
                        }
                        return {
                            timestamp: new Date(parseInt(j.__REALTIME_TIMESTAMP) / 1000).toISOString(),
                            eventType: authResult === 'success'
                                ? 'logon'
                                : authResult === 'failure'
                                    ? 'logon_failed'
                                    : authResult === 'logoff'
                                        ? 'logoff'
                                        : 'system',
                            source,
                            eventId: parseInt(j.PRIORITY, 10) || 0,
                            level: Number.isFinite(priority) && priority <= 3 ? 'error' : (authResult === 'failure' ? 'warning' : 'info'),
                            message,
                            userName,
                            computer: j._HOSTNAME || '',
                            sourceIp,
                            sourcePort,
                            sourceHost: j._HOSTNAME || '',
                            sessionType,
                            authMethod,
                            failureReason,
                            authResult,
                        };
                    })
                        .filter((entry) => !!entry);
                    resolve(events);
                }
                catch {
                    resolve([]);
                }
            });
        });
    }
}
exports.SystemEventsCollector = SystemEventsCollector;
//# sourceMappingURL=system-events.js.map