<?php
/********************************************************************/
/* Nagios XI AI Helper – host add/remove via natural-language prompt */
/********************************************************************/
require_once(dirname(__FILE__) . '/common.inc.php');
require_once(dirname(__FILE__) . '/utils-users.inc.php');
require_once(dirname(__FILE__) . '/components/ccm/bootstrap.php');



init_session();
check_nagios_session_protector();

header("Content-Type: application/json");

function respond(bool $success, string $response = "", $data = null, string $error = "") {
    echo json_encode([
        'success'  => $success,
        'response' => $response,
        'data'     => $data,
        'error'    => $error
    ]);
    exit;
}

function fail(string $msg) {
    http_response_code(400);
    respond(false, "", null, $msg);
}


function replace_placeholders(array $arr, array $replacements): array {
    $json = json_encode($arr);
    foreach ($replacements as $key=>$value) {
        $json = str_replace($key, $value, $json);
    }
    return json_decode($json, true);
}


function inject_placeholders(array $services, string $ip, ?string $token, ?string $community): array {
    foreach ($services as &$service) {
        if (isset($service['check_command'])) {
            $service['check_command'] = str_replace(
                ['IP', 'TOKEN', 'COMMUNITY'],
                [$ip, $token ?? '', $community ?? 'public'],
                $service['check_command']
            );}}
     return $services;
}

function with_defaults(array $service, array $defaults): array{
    foreach ($defaults as $key => $defaultValue) {
        if (!array_key_exists($key, $service)) {
            $service[$key] = $defaultValue;}}
    return $service;
}

function ncpa_nodes(string $ip, string $token, string $section): array {
    $url = "https://{$ip}:5693/api/{$section}?token=".urlencode($token);
    $context = stream_context_create(['ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]]);
    $raw = @file_get_contents($url, false, $context);
    return json_decode($raw ?? '', true) ?? [];
}

function ncpa_disk_metric(string $mount): string {
    $mount = trim($mount, '/');
    return 'disk/logical/|' . str_replace('/', '|', $mount);
}

/* -------------------- input ----------------------- */
$prompt = trim($_POST['prompt'] ?? '');
if ($prompt === '') {
    fail("No prompt provided.");
}

const CONFIDENCE_THRESHOLD = 0.50;
// classify action 
$cmd = get_root_dir() . '/var/nagios/xihelper/venv/bin/python ' . get_root_dir() . '/html/includes/classifiers/classify.py --action ' . escapeshellarg($prompt);
$classification_out = shell_exec($cmd);
$classification_json = json_decode(trim($classification_out), true);
$action = $classification_json['label'] ?? 'unknown';
$confidence_action = $classification_json['score'] ?? 0;

if (empty($classification_json['label'])) {
    fail("No tools detected. Please Download & Install Dependencies.");
}

if ($confidence_action < CONFIDENCE_THRESHOLD) {
    fail("Low confidence – do you want to add or remove a host?");

}
if ($action === 'unknown') {
    fail("Sorry, I didn't understand the request.");
    exit;
}
/* -------------------- extraction ------------------ */
if (preg_match('/\b((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3})\b/', $prompt, $exp)) {
    $ip = $exp[1];
} else {$ip = 'ADDR';
}

if (preg_match('/["\'({\[<]\s*([A-Za-z0-9._~%+-]{3,128})\s*[)"\'}\]>]/', $prompt, $exp)) {
    $token  = trim($exp[1]);
    $community = trim($exp[1]);
} else {
    $token  = '';
    $community = 'public';}

if (preg_match('/\b(?:https?:\/\/)?(?:www\.)?([A-Za-z0-9.-]+\.[A-Za-z]{2,})\b/i', $prompt, $exp)) {
    $hostname = $exp[1];
} else {$hostname = $ip;
}

if ($ip === 'ADDR' && $hostname !== '') {$ip = $hostname;}

define('CONFIRM_FLAG', 'confirm');

/* ==================== DELETE ====================== */
if ($action === 'delete_host') {

    if (empty($_POST[CONFIRM_FLAG])) {

        $host_id = nagiosql_get_host_id($hostname);
        if ($host_id <= 0) {
            fail("Host '{$hostname}' not found in CCM database.");
        }

        respond(
            true,
            "You are about to delete host '{$hostname}'. Confirm?",
            [
                'type'   => 'confirm_delete',
                'action' => 'delete_host',
                'host'   => $hostname
            ]
        );
        exit;
    }

    $host_id = nagiosql_get_host_id($hostname);

    list($code, $msg) = delete_object('host', $host_id);

    if ($code === 0) {
        submit_command(COMMAND_NAGIOSCORE_APPLYCONFIG);
        respond(
            true,
            "Monitoring stopped and host '{$hostname}' deleted successfully."
        );
    } else {
        fail("Failed to delete host '{$hostname}'.");
    }
}

/* ==================== ADD ========================= */
// classify host type 
$cmd = get_root_dir() . '/var/nagios/xihelper/venv/bin/python ' . get_root_dir() . '/html/includes/classifiers/classify.py --hosttype ' . escapeshellarg($prompt);
$classification_out = shell_exec($cmd);
$classification_json = json_decode(trim($classification_out), true);
$host_type = $classification_json['label'] ?? 'unknown';
$confidence_host = $classification_json['score'] ?? 0;

if ($confidence_host < CONFIDENCE_THRESHOLD) fail("Low confidence ($confidence_host) – host type unclear.");

if ($action === 'add_host') {
    $missing = [];

    if ($ip === 'ADDR' || empty($ip)) $missing[] = 'address or hostname';

    if ($host_type === 'ncpa' && empty($token)) $missing[] = 'NCPA token';
    if ($host_type === 'snmp' && empty($community)) $missing[] = 'SNMP community string';

    if (!empty($missing)) {
        fail("Missing required information to start monitoring: " . implode(', ', $missing) .". ");
        exit;
    }
}

/* reachability / token - community string */
function is_host_ready(string $ip, string $host_type, ?string $token=null, ?string $community = null): bool {
    if ($host_type === 'website') {
        $ip_addr = gethostbyname($ip);
        if ($ip_addr === $ip) return false;
        foreach ([80,443] as $port) {
            $sock=@fsockopen($ip_addr,$port,$errno,$errstr,2);
            if($sock){fclose($sock);return true;}
        }
        return false;
    }
    $alive = (exec("ping -c1 -w2 ".escapeshellarg($ip)." >/dev/null 2>&1; echo $?") === '0');
    if ($host_type === 'ncpa') {
        if (empty($token)) return false;

        $url = "https://{$ip}:5693/testconnect/?token=" . urlencode($token);
        $context = stream_context_create([
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true]
        ]);

        $raw = @file_get_contents($url, false, $context);
        if (!$raw) return false;

        $json = json_decode($raw, true);
        return (isset($json['value']) && stripos($json['value'], 'success') !== false);
    }

    if ($host_type === 'snmp') {
        $command = sprintf("snmpget -v2c -c %s -Oqv %s 1.3.6.1.2.1.1.1.0",
            escapeshellarg($community), escapeshellarg($ip));
        exec($command . " 2>/dev/null", $out, $code);
        return $alive && $code === 0 && !empty($out);
    }
    return $alive;
}

if (!is_host_ready($ip, $host_type, $token, $community)) {
    $message = ($host_type === 'ncpa')
        ? "Host $ip ($host_type) unreachable or token invalid — config not applied."
        : "Host $ip ($host_type) unreachable — config not applied.";
    fail($message);
}

// load templates 
$template_dir = get_root_dir() . "/html/includes/classifiers/service-templates/{$host_type}";
$host_obj = json_decode(@file_get_contents("$template_dir/host.json"), true);
$services_arr = json_decode(@file_get_contents("$template_dir/services.json"), true);
if (!$host_obj || !$services_arr) fail('Bad template files for '.$host_type);

// build configs 
$replacements = ['HOSTNAME'=>$hostname,'ADDR'=>$ip,'TOKEN'=>$token, 'COMMUNITY'=>$community];
$host_config = replace_placeholders($host_obj, $replacements);

$services_config = inject_placeholders(replace_placeholders($services_arr,$replacements), $ip,$token,$community);

$services_defaults = [
    'use'=>'xiwizard_ncpa_service','contacts'=>'nagiosadmin',
    'max_check_attempts'=>5,'check_interval'=>5,'retry_interval'=>1,
    'check_period'=>'xi_timeperiod_24x7',
    'notification_interval'=>60,'notification_period'=>'xi_timeperiod_24x7',
    '_xiwizard'=>'ncpa','register'=>1,'applyconfig'=>0
];

if ($host_type === 'ncpa') {
    $disks = ncpa_nodes($ip, $token, 'disk/logical')['logical'] ?? [];

    foreach ($disks as $key => $val) {
        $label = ltrim($key, '|');
        $clean_label = preg_replace('/[~!$%^&*"\'|<>?()=]/', '_', $label);

        $services_config[] = with_defaults([
            'host_name' => "$hostname",
            'service_description' => "Disk Usage on /$clean_label",
            'check_command' => "check_xi_ncpa!-t $token -P 5693 -M '" . ncpa_disk_metric($label) . "' -w '70' -c '90'"
        ], $services_defaults);
    }

    $ifaces = ncpa_nodes($ip, $token, 'interface')['interface'] ?? [];

    foreach ($ifaces as $iface => $_) {
        $clean_iface = preg_replace('/[~!$%^&*"\'|<>?()=]/', '_', $iface);
        foreach (['bytes_recv' => 'Inbound', 'bytes_sent' => 'Outbound'] as $metric => $dir) {
            $services_config[] = with_defaults([
                'host_name' => "$hostname",
                'service_description' => "$clean_iface Bandwidth - $dir",
                'check_command' => "check_xi_ncpa!-t $token -P 5693 -M 'interface/$iface/$metric' -d -u M -w '10' -c '100'"
            ], $services_defaults);
        }
    }
}

$config_dir  = "/usr/local/nagios/etc/import/";
$config_path = $config_dir . $hostname . ".cfg";
// Building config file
$out = "define host {\n";
foreach ($host_config as $key => $val) {
    $out .= "    $key    $val\n";}
$out .= "}\n\n";

foreach ($services_config as $service) {
    $out .= "define service {\n";
    foreach ($service as $key => $val) {
        $out .= "    $key    $val\n";}
    $out .= "}\n\n";}

if (file_put_contents($config_path, $out) === false) {
    fail("Failed to write configuration file: $config_path");}

$command_id = submit_command(COMMAND_NAGIOSCORE_APPLYCONFIG);

if ($command_id > 0) {
    respond(true, "Monitoring started for $host_type host: $hostname");
} else {
    fail("Failed to queue Nagios Core apply configuration.");
}
exit;
