<?php
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
error_reporting(0);

define('DISPLAY_API_VERSION', '1.0.0');
define('SVXLINK_CONF', '/etc/svxlink/svxlink.conf');
define('SVXLINK_LOG', '/var/log/svxlink');
define('DISPLAY_TOKEN_FILE', '/etc/svxlink/display-api-token');
define('DTMF_FIFO', '/tmp/dtmf_svx');

function display_token() {
    $env = getenv('DISPLAY_API_TOKEN');
    if ($env !== false && trim($env) !== '') return trim($env);
    if (is_readable(DISPLAY_TOKEN_FILE)) return trim(file_get_contents(DISPLAY_TOKEN_FILE));
    return '';
}

function request_token() {
    $headers = function_exists('getallheaders') ? getallheaders() : array();
    if (isset($headers['X-Display-Token'])) return trim($headers['X-Display-Token']);
    if (isset($headers['x-display-token'])) return trim($headers['x-display-token']);
    if (isset($_REQUEST['token'])) return trim($_REQUEST['token']);
    return '';
}

function require_token_for_write() {
    $configured = display_token();
    if ($configured === '') return true;
    if (!hash_equals($configured, request_token())) {
        http_response_code(403);
        echo json_encode(array('ok' => false, 'error' => 'Invalid display API token'));
        exit;
    }
    return true;
}

function read_conf() {
    if (is_readable(SVXLINK_CONF)) {
        $conf = parse_ini_file(SVXLINK_CONF, true, INI_SCANNER_RAW);
        return is_array($conf) ? $conf : array();
    }
    return array();
}

function conf_value($conf, $section, $key, $default = '') {
    return isset($conf[$section]) && isset($conf[$section][$key]) ? trim((string)$conf[$section][$key]) : $default;
}

function split_list($value) {
    $value = trim((string)$value);
    if ($value === '') return array();
    $parts = preg_split('/[\s,]+/', $value);
    return array_values(array_filter(array_map('trim', $parts), 'strlen'));
}

function tail_lines($file, $count = 800) {
    if (!is_readable($file)) return array();
    $cmd = 'tail -n ' . intval($count) . ' ' . escapeshellarg($file) . ' 2>/dev/null';
    $out = array();
    exec($cmd, $out);
    return $out;
}

function last_line_matching($lines, $regex) {
    for ($i = count($lines) - 1; $i >= 0; $i--) {
        if (preg_match($regex, $lines[$i])) return $lines[$i];
    }
    return '';
}

function radio_status($lines) {
    $line = last_line_matching($lines, '/Turning the transmitter|squelch is|Talker start on|Talker stop on/i');
    if ($line === '') return 'Unknown';
    if (stripos($line, 'Turning the transmitter ON') !== false) return 'TX';
    if (stripos($line, 'Talker start on') !== false) return 'RX';
    if (stripos($line, 'squelch is OPEN') !== false) return 'RX';
    return 'Listening';
}

function reflector_status($lines) {
    $line = last_line_matching($lines, '/Authentication OK|Connection established|Heartbeat timeout|No route to host|Connection refused|Connection timed out|Locally ordered disconnect|Deactivating link|Activating link/i');
    if ($line === '') return 'No status';
    if (preg_match('/Authentication OK|Connection established|Activating link/i', $line)) return 'Connected';
    if (preg_match('/Heartbeat timeout|No route to host|Connection refused|Connection timed out|Locally ordered disconnect|Deactivating link/i', $line)) return 'Not connected';
    return 'No status';
}

function process_running($name) {
    $out = array();
    exec('pidof ' . escapeshellarg($name) . ' 2>/dev/null', $out);
    return count($out) > 0;
}

function active_modules($conf, $lines) {
    $known = array();
    foreach ($conf as $section => $items) {
        if (isset($items['MODULES'])) {
            foreach (split_list($items['MODULES']) as $m) $known[$m] = 'Off';
        }
    }
    foreach ($lines as $line) {
        if (preg_match('/Activating module\s+([^\s:]+)/i', $line, $m)) $known[rtrim($m[1], ':')] = 'On';
        if (preg_match('/Deactivating module\s+([^\s:]+)/i', $line, $m)) $known[rtrim($m[1], ':')] = 'Off';
    }
    $out = array();
    foreach ($known as $name => $state) $out[] = array('name' => $name, 'active' => $state === 'On');
    return $out;
}

function selected_tg($lines) {
    $line = last_line_matching($lines, '/Selecting TG #?\s*([0-9]+)/i');
    if ($line && preg_match('/Selecting TG #?\s*([0-9]+)/i', $line, $m)) return $m[1];
    return '';
}

function last_heard($lines, $limit = 12) {
    $heard = array();
    $seen = array();
    for ($i = count($lines) - 1; $i >= 0 && count($heard) < $limit; $i--) {
        $line = $lines[$i];
        if (!preg_match('/^(.{19}).*: Talker (start|stop) on TG #?\s*([0-9]+):\s*(.+)$/i', $line, $m)) continue;
        $time = trim($m[1]);
        $event = strtolower($m[2]);
        $tg = trim($m[3]);
        $call = trim($m[4]);
        if ($call === '' || strlen($call) > 24) continue;
        $key = $call . '#' . $tg;
        if (isset($seen[$key])) continue;
        $seen[$key] = true;
        $heard[] = array(
            'time' => $time,
            'time_local' => $time,
            'mode' => 'SVXLink',
            'source_mode' => 'SVXLink',
            'callsign' => $call,
            'station' => $call,
            'target' => 'TG ' . $tg,
            'talkgroup' => $tg,
            'target_name' => '',
            'talkgroup_name' => '',
            'src' => 'SVXRef',
            'source_system' => 'SVXRef',
            'tx' => $event === 'start' ? 'ON' : 'OFF'
        );
    }
    return $heard;
}

function tg_list($conf) {
    $default = conf_value($conf, 'ReflectorLogic', 'DEFAULT_TG', '');
    $monitor = split_list(conf_value($conf, 'ReflectorLogic', 'MONITOR_TGS', ''));
    $out = array();
    if ($default !== '') $out[] = array('id' => $default, 'name' => 'Default TG', 'default' => true, 'monitored' => in_array($default, $monitor));
    foreach ($monitor as $tg) {
        if ($tg !== $default) $out[] = array('id' => $tg, 'name' => 'Monitor TG', 'default' => false, 'monitored' => true);
    }
    return $out;
}

function send_dtmf_command($command) {
    $ok = file_put_contents(DTMF_FIFO, $command . PHP_EOL, LOCK_EX);
    if ($ok === false) {
        http_response_code(500);
        echo json_encode(array('ok' => false, 'error' => 'Could not write DTMF command to ' . DTMF_FIFO));
        exit;
    }
    echo json_encode(array('ok' => true, 'command' => $command));
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    require_token_for_write();
    $action = isset($_POST['action']) ? trim($_POST['action']) : '';
    $value = isset($_POST['value']) ? trim($_POST['value']) : '';
    if ($action === 'dtmf') {
        $cmd = preg_replace('/[^0-9A-Da-d\*#]/', '', $value);
        if ($cmd === '') { http_response_code(400); echo json_encode(array('ok'=>false,'error'=>'Missing DTMF value')); exit; }
        send_dtmf_command(strtoupper($cmd));
    }
    if ($action === 'active_tg') {
        $tg = preg_replace('/[^0-9]/', '', $value);
        if ($tg === '') { http_response_code(400); echo json_encode(array('ok'=>false,'error'=>'Missing TG value')); exit; }
        send_dtmf_command('91' . $tg . '#');
    }
    if ($action === 'monitor_tg') {
        $tg = preg_replace('/[^0-9]/', '', $value);
        if ($tg === '') { http_response_code(400); echo json_encode(array('ok'=>false,'error'=>'Missing TG value')); exit; }
        send_dtmf_command('94' . $tg . '#');
    }
    http_response_code(400);
    echo json_encode(array('ok' => false, 'error' => 'Unknown action'));
    exit;
}

$conf = read_conf();
$lines = tail_lines(SVXLINK_LOG, 1200);
$logicNames = split_list(conf_value($conf, 'GLOBAL', 'LOGICS', ''));
$modules = active_modules($conf, $lines);
$defaultTg = conf_value($conf, 'ReflectorLogic', 'DEFAULT_TG', '');
$activeTg = selected_tg($lines);
if ($activeTg === '') $activeTg = $defaultTg;
$monitorTgs = split_list(conf_value($conf, 'ReflectorLogic', 'MONITOR_TGS', ''));

$response = array(
    'ok' => true,
    'api' => 'mmdvm-display-svxlink',
    'api_version' => DISPLAY_API_VERSION,
    'backend' => 'SVXLink',
    'callsign' => defined('CALLSIGN') ? CALLSIGN : conf_value($conf, 'SimplexLogic', 'CALLSIGN', conf_value($conf, 'RepeaterLogic', 'CALLSIGN', '')),
    'network_name' => conf_value($conf, 'ReflectorLogic', 'HOSTS', ''),
    'system' => array(
        'process' => process_running('svxlink') ? 'Running' : 'Stopped',
        'reboot' => trim(shell_exec('uptime -s 2>/dev/null')),
        'mode' => count($logicNames) ? implode(', ', $logicNames) : 'SVXLink'
    ),
    'radio_status' => radio_status($lines),
    'reflector_status' => reflector_status($lines),
    'reflector_host' => conf_value($conf, 'ReflectorLogic', 'HOST', conf_value($conf, 'ReflectorLogic', 'HOSTS', '')),
    'logics' => $logicNames,
    'modules' => $modules,
    'tg' => array(
        'default' => $defaultTg,
        'active' => $activeTg,
        'monitor' => $monitorTgs,
        'list' => tg_list($conf)
    ),
    'last_heard' => last_heard($lines, isset($_GET['limit']) ? intval($_GET['limit']) : 12),
    'controls' => array(
        'dtmf' => true,
        'active_tg' => true,
        'monitor_tg' => true,
        'token_required' => display_token() !== ''
    )
);

echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
