<?php
$viewProgramType = isset($_POST['program_type_view']) ? strtolower(trim((string)$_POST['program_type_view'])) : 'all';
if ($viewProgramType !== 'remote' && $viewProgramType !== 'vpn') {
    $viewProgramType = 'all';
}

$sub_menu = ($viewProgramType === 'vpn') ? '100331' : '100330';
include_once('./_common.php');

check_demo();
$auth_menu = isset($auth[$sub_menu]) ? $sub_menu : '100330';
auth_check($auth[$auth_menu], 'w');
check_admin_token();

if (!isset($g5['remote_program_catalog_table'])) {
    $g5['remote_program_catalog_table'] = (isset($g5['table_prefix']) ? $g5['table_prefix'] : 'g5_') . 'remote_program_catalog';
}
if (!isset($g5['remote_program_catalog_setting_table'])) {
    $g5['remote_program_catalog_setting_table'] = (isset($g5['table_prefix']) ? $g5['table_prefix'] : 'g5_') . 'remote_program_catalog_setting';
}

function oi_remote_program_catalog_admin_ensure_table($table)
{
    sql_query(" CREATE TABLE IF NOT EXISTS `{$table}` (
        `rpc_id` int(11) NOT NULL AUTO_INCREMENT,
        `program_key` varchar(80) NOT NULL DEFAULT '',
        `program_type` varchar(10) NOT NULL DEFAULT 'remote',
        `name` varchar(255) NOT NULL DEFAULT '',
        `official_url` varchar(255) NOT NULL DEFAULT '',
        `aliases_json` text NOT NULL,
        `download_windows` varchar(255) NOT NULL DEFAULT '',
        `download_macos` varchar(255) NOT NULL DEFAULT '',
        `download_linux` varchar(255) NOT NULL DEFAULT '',
        `download_android` varchar(255) NOT NULL DEFAULT '',
        `download_ios` varchar(255) NOT NULL DEFAULT '',
        `sort_order` int(11) NOT NULL DEFAULT '0',
        `is_active` tinyint(4) NOT NULL DEFAULT '1',
        `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
        `updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
        PRIMARY KEY (`rpc_id`),
        UNIQUE KEY `uk_type_program_key` (`program_type`,`program_key`),
        KEY `idx_program_type` (`program_type`),
        KEY `idx_sort_order` (`sort_order`),
        KEY `idx_is_active` (`is_active`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ", false);

    $desc = sql_query(" DESCRIBE `{$table}` ", false);
    $cols = array();
    if ($desc) {
        while ($row = sql_fetch_array($desc)) {
            $cols[] = $row['Field'];
        }
    }

    if (!in_array('program_type', $cols)) {
        sql_query(" ALTER TABLE `{$table}` ADD `program_type` varchar(10) NOT NULL DEFAULT 'remote' AFTER `program_key` ", false);
        sql_query(" ALTER TABLE `{$table}` ADD KEY `idx_program_type` (`program_type`) ", false);
    }

    $indexes = array();
    $idxRows = sql_query(" SHOW INDEX FROM `{$table}` ", false);
    if ($idxRows) {
        while ($idxRow = sql_fetch_array($idxRows)) {
            $indexes[$idxRow['Key_name']] = true;
        }
    }

    if (isset($indexes['uk_program_key'])) {
        sql_query(" ALTER TABLE `{$table}` DROP INDEX `uk_program_key` ", false);
    }
    if (!isset($indexes['uk_type_program_key'])) {
        sql_query(" ALTER TABLE `{$table}` ADD UNIQUE KEY `uk_type_program_key` (`program_type`,`program_key`) ", false);
    }
}

function oi_remote_program_catalog_admin_ensure_setting_table($table)
{
    sql_query(" CREATE TABLE IF NOT EXISTS `{$table}` (
        `setting_key` varchar(120) NOT NULL DEFAULT '',
        `setting_value` text NOT NULL,
        `updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
        PRIMARY KEY (`setting_key`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ", false);
}

function oi_remote_program_allowlist_defaults_admin()
{
    return array(
        'exact' => array(
            'apps.apple.com',
            'itunes.apple.com',
            'play.google.com',
            'apps.microsoft.com',
            'remotedesktop.google.com',
            'sj.qq.com'
        ),
        'suffix' => array(
            'rpcviewer.com',
            'rustdesk.com',
            'openvpn.net',
            'wireguard.com',
            'strongswan.org',
            'cisco.com',
            'microsoft.com',
            'teamviewer.com',
            'anydesk.com',
            'google.com',
            'logmein.com',
            'gotomypc.com',
            'remotepc.com',
            'splashtop.com',
            'realvnc.com',
            'sunlogin.oray.com',
            'anyviewer.com'
        )
    );
}

function oi_remote_program_allowlist_parse_text($text)
{
    $list = array();
    $parts = preg_split('/[\r\n,]+/', (string)$text);
    if (is_array($parts)) {
        foreach ($parts as $part) {
            $part = strtolower(trim((string)$part));
            $part = preg_replace('/[^a-z0-9\.-]/', '', $part);
            if ($part !== '') {
                $list[] = $part;
            }
        }
    }

    return array_values(array_unique($list));
}

function oi_remote_program_allowlist_load_admin($table)
{
    $defaults = oi_remote_program_allowlist_defaults_admin();
    $allowExact = $defaults['exact'];
    $allowSuffix = $defaults['suffix'];

    $exists = sql_fetch(" SHOW TABLES LIKE '{$table}' ");
    if (!$exists) {
        return array('exact' => $allowExact, 'suffix' => $allowSuffix);
    }

    $rowExact = sql_fetch(" SELECT setting_value FROM `{$table}` WHERE setting_key = 'allow_exact_hosts' ");
    $rowSuffix = sql_fetch(" SELECT setting_value FROM `{$table}` WHERE setting_key = 'allow_suffix_hosts' ");

    if (!empty($rowExact['setting_value'])) {
        $decoded = json_decode($rowExact['setting_value'], true);
        if (is_array($decoded) && !empty($decoded)) {
            $allowExact = array_values(array_unique(array_map('strtolower', array_map('trim', $decoded))));
        }
    }
    if (!empty($rowSuffix['setting_value'])) {
        $decoded = json_decode($rowSuffix['setting_value'], true);
        if (is_array($decoded) && !empty($decoded)) {
            $allowSuffix = array_values(array_unique(array_map('strtolower', array_map('trim', $decoded))));
        }
    }

    return array('exact' => $allowExact, 'suffix' => $allowSuffix);
}

function oi_remote_program_allowlist_save_admin($table, $exactList, $suffixList)
{
    $nowSql = sql_escape_string(G5_TIME_YMDHIS);
    $exactJson = sql_escape_string(json_encode(array_values($exactList), JSON_UNESCAPED_UNICODE));
    $suffixJson = sql_escape_string(json_encode(array_values($suffixList), JSON_UNESCAPED_UNICODE));

    sql_query(" REPLACE INTO `{$table}` SET setting_key='allow_exact_hosts', setting_value='{$exactJson}', updated_at='{$nowSql}' ", false);
    sql_query(" REPLACE INTO `{$table}` SET setting_key='allow_suffix_hosts', setting_value='{$suffixJson}', updated_at='{$nowSql}' ", false);
}

function oi_remote_program_catalog_make_key($name)
{
    $name = strtolower(trim((string)$name));
    $name = preg_replace('/[^a-z0-9]+/', '_', $name);
    $name = trim($name, '_');

    return substr($name, 0, 80);
}

function oi_remote_program_catalog_parse_aliases($aliasesText)
{
    $aliases = array();
    $parts = preg_split('/[\r\n,]+/', (string)$aliasesText);
    if (is_array($parts)) {
        foreach ($parts as $part) {
            $part = trim((string)$part);
            if ($part !== '') {
                $aliases[] = $part;
            }
        }
    }

    return array_values(array_unique($aliases));
}

function oi_remote_program_catalog_insert_defaults_by_type($table, $programType)
{
    if (!function_exists('oi_remote_program_catalog_default')) {
        return 0;
    }

    $defaults = oi_remote_program_catalog_default();
    if (!is_array($defaults) || empty($defaults)) {
        return 0;
    }

    $count = 0;
    $now = G5_TIME_YMDHIS;
    $sort = 0;

    foreach ($defaults as $programKey => $row) {
        if (!is_array($row)) {
            continue;
        }

        $rowType = isset($row['program_type']) ? strtolower(trim((string)$row['program_type'])) : 'remote';
        if ($rowType !== 'vpn') {
            $rowType = 'remote';
        }

        if ($rowType !== $programType) {
            continue;
        }

        $programKey = strtolower(trim((string)$programKey));
        $programKey = preg_replace('/[^a-z0-9_\-]/', '', $programKey);
        if ($programKey === '') {
            continue;
        }

        $name = isset($row['name']) ? trim((string)$row['name']) : '';
        if ($name === '') {
            continue;
        }

        $aliases = isset($row['aliases']) && is_array($row['aliases']) ? array_values($row['aliases']) : array();
        $aliasesJson = json_encode($aliases, JSON_UNESCAPED_UNICODE);
        if (!is_string($aliasesJson)) {
            $aliasesJson = '[]';
        }

        $download = isset($row['download_url']) && is_array($row['download_url']) ? $row['download_url'] : array();
        $sort++;

        $programKeySql = sql_escape_string($programKey);
        $programTypeSql = sql_escape_string($rowType);
        $nameSql = sql_escape_string($name);
        $officialUrlSql = sql_escape_string(trim((string)(isset($row['official_url']) ? $row['official_url'] : '')));
        $aliasesJsonSql = sql_escape_string($aliasesJson);
        $winUrlSql = sql_escape_string(trim((string)(isset($download['windows']) ? $download['windows'] : '')));
        $macUrlSql = sql_escape_string(trim((string)(isset($download['macos']) ? $download['macos'] : '')));
        $linuxUrlSql = sql_escape_string(trim((string)(isset($download['linux']) ? $download['linux'] : '')));
        $androidUrlSql = sql_escape_string(trim((string)(isset($download['android']) ? $download['android'] : '')));
        $iosUrlSql = sql_escape_string(trim((string)(isset($download['ios']) ? $download['ios'] : '')));
        $nowSql = sql_escape_string($now);

        $sql = " INSERT INTO `{$table}`
                    SET program_key = '{$programKeySql}',
                        program_type = '{$programTypeSql}',
                        name = '{$nameSql}',
                        official_url = '{$officialUrlSql}',
                        aliases_json = '{$aliasesJsonSql}',
                        download_windows = '{$winUrlSql}',
                        download_macos = '{$macUrlSql}',
                        download_linux = '{$linuxUrlSql}',
                        download_android = '{$androidUrlSql}',
                        download_ios = '{$iosUrlSql}',
                        sort_order = '{$sort}',
                        is_active = '1',
                        created_at = '{$nowSql}',
                        updated_at = '{$nowSql}' ";
        sql_query($sql, false);
        $count++;
    }

    return $count;
}

function oi_remote_program_clean_url($url)
{
    $url = trim((string)$url);
    if ($url === '') {
        return '';
    }

    if (!preg_match('/^https?:\/\//i', $url)) {
        return '';
    }

    return substr($url, 0, 255);
}

function oi_remote_program_is_allowed_host($host)
{
    $host = strtolower(trim((string)$host));
    if ($host === '') {
        return false;
    }

    global $oi_rpc_allow_exact_hosts, $oi_rpc_allow_suffix_hosts;

    $exactHosts = is_array($oi_rpc_allow_exact_hosts) ? $oi_rpc_allow_exact_hosts : array();
    $suffixHosts = is_array($oi_rpc_allow_suffix_hosts) ? $oi_rpc_allow_suffix_hosts : array();

    if (in_array($host, $exactHosts, true)) {
        return true;
    }

    foreach ($suffixHosts as $suffix) {
        if ($host === $suffix || preg_match('/\.'.preg_quote($suffix, '/').'$/', $host)) {
            return true;
        }
    }

    return false;
}

function oi_remote_program_validate_url($url)
{
    $url = oi_remote_program_clean_url($url);
    if ($url === '') {
        return array('ok' => true, 'url' => '', 'reason' => '');
    }

    $parts = @parse_url($url);
    $host = isset($parts['host']) ? strtolower(trim((string)$parts['host'])) : '';
    if ($host === '') {
        return array('ok' => false, 'url' => '', 'reason' => 'URL에서 host를 해석할 수 없습니다.');
    }

    if (!oi_remote_program_is_allowed_host($host)) {
        return array('ok' => false, 'url' => '', 'reason' => '허용되지 않은 도메인입니다: '.$host);
    }

    return array('ok' => true, 'url' => $url, 'reason' => '');
}

oi_remote_program_catalog_admin_ensure_table($g5['remote_program_catalog_table']);
oi_remote_program_catalog_admin_ensure_setting_table($g5['remote_program_catalog_setting_table']);

$allowlistDefaults = oi_remote_program_allowlist_defaults_admin();
$allowExactPosted = isset($_POST['allow_exact_text']) ? oi_remote_program_allowlist_parse_text($_POST['allow_exact_text']) : $allowlistDefaults['exact'];
$allowSuffixPosted = isset($_POST['allow_suffix_text']) ? oi_remote_program_allowlist_parse_text($_POST['allow_suffix_text']) : $allowlistDefaults['suffix'];

if (empty($allowExactPosted)) {
    $allowExactPosted = $allowlistDefaults['exact'];
}
if (empty($allowSuffixPosted)) {
    $allowSuffixPosted = $allowlistDefaults['suffix'];
}

oi_remote_program_allowlist_save_admin($g5['remote_program_catalog_setting_table'], $allowExactPosted, $allowSuffixPosted);

$allowlistLoaded = oi_remote_program_allowlist_load_admin($g5['remote_program_catalog_setting_table']);
$oi_rpc_allow_exact_hosts = $allowlistLoaded['exact'];
$oi_rpc_allow_suffix_hosts = $allowlistLoaded['suffix'];

$mode = isset($_POST['mode']) ? trim((string)$_POST['mode']) : '';
if ($mode === 'reset_defaults') {
    if ($viewProgramType === 'remote' || $viewProgramType === 'vpn') {
        $typeSql = sql_escape_string($viewProgramType);
        sql_query(" DELETE FROM `{$g5['remote_program_catalog_table']}` WHERE program_type = '{$typeSql}' ", false);
        $restored = oi_remote_program_catalog_insert_defaults_by_type($g5['remote_program_catalog_table'], $viewProgramType);
        $label = ($viewProgramType === 'vpn') ? 'VPN 접속S/W' : '원격제어 S/W';
        alert($label.' 기본값으로 복원되었습니다. ('.$restored.'건)');
        goto_url('./remote_program_catalog.php?program_type='.$viewProgramType);
    }

    sql_query(" DELETE FROM `{$g5['remote_program_catalog_table']}` ", false);
    alert('기본 카탈로그로 복원되었습니다.');
    goto_url('./remote_program_catalog.php');
}

$programKeys = isset($_POST['program_key']) && is_array($_POST['program_key']) ? $_POST['program_key'] : array();
$programTypes = isset($_POST['row_program_type']) && is_array($_POST['row_program_type']) ? $_POST['row_program_type'] : array();
$names = isset($_POST['name']) && is_array($_POST['name']) ? $_POST['name'] : array();
$aliasesTexts = isset($_POST['aliases_text']) && is_array($_POST['aliases_text']) ? $_POST['aliases_text'] : array();
$officialUrls = isset($_POST['official_url']) && is_array($_POST['official_url']) ? $_POST['official_url'] : array();
$downloadWindows = isset($_POST['download_windows']) && is_array($_POST['download_windows']) ? $_POST['download_windows'] : array();
$downloadMacos = isset($_POST['download_macos']) && is_array($_POST['download_macos']) ? $_POST['download_macos'] : array();
$downloadLinux = isset($_POST['download_linux']) && is_array($_POST['download_linux']) ? $_POST['download_linux'] : array();
$downloadAndroid = isset($_POST['download_android']) && is_array($_POST['download_android']) ? $_POST['download_android'] : array();
$downloadIos = isset($_POST['download_ios']) && is_array($_POST['download_ios']) ? $_POST['download_ios'] : array();
$sortOrders = isset($_POST['sort_order']) && is_array($_POST['sort_order']) ? $_POST['sort_order'] : array();
$rowActive = isset($_POST['row_is_active']) && is_array($_POST['row_is_active']) ? $_POST['row_is_active'] : array();

$totalRows = count($names);
if ($totalRows < 1) {
    alert('저장할 데이터가 없습니다.');
}

if ($viewProgramType === 'remote' || $viewProgramType === 'vpn') {
    $typeSql = sql_escape_string($viewProgramType);
    sql_query(" DELETE FROM `{$g5['remote_program_catalog_table']}` WHERE program_type = '{$typeSql}' ", false);
} else {
    sql_query(" DELETE FROM `{$g5['remote_program_catalog_table']}` ", false);
}

$usedKeys = array();
$insertCount = 0;
$now = G5_TIME_YMDHIS;

for ($i=0; $i<$totalRows; $i++) {
    $name = trim(isset($names[$i]) ? (string)$names[$i] : '');
    if ($name === '') {
        continue;
    }

    if ($viewProgramType === 'remote' || $viewProgramType === 'vpn') {
        $programType = $viewProgramType;
    } else {
        $programType = isset($programTypes[$i]) ? strtolower(trim((string)$programTypes[$i])) : 'remote';
        if ($programType !== 'vpn') {
            $programType = 'remote';
        }
    }

    $programKey = trim(isset($programKeys[$i]) ? (string)$programKeys[$i] : '');
    $programKey = strtolower(preg_replace('/[^a-z0-9_\-]/', '', $programKey));
    if ($programKey === '') {
        $programKey = oi_remote_program_catalog_make_key($name);
    }
    if ($programKey === '') {
        continue;
    }

    // 타입별 분리를 위해 key 중복 검사는 type+key 조합으로 수행
    $keyByType = $programType . '|' . $programKey;

    if (isset($usedKeys[$keyByType])) {
        alert('중복된 program_key가 있습니다: '.$programKey.' / type='.$programType.' (row '.($i + 1).')');
    }
    $usedKeys[$keyByType] = true;

    $aliases = oi_remote_program_catalog_parse_aliases(isset($aliasesTexts[$i]) ? $aliasesTexts[$i] : '');
    $aliasesJson = json_encode($aliases, JSON_UNESCAPED_UNICODE);
    if (!is_string($aliasesJson)) {
        $aliasesJson = '[]';
    }

    $officialUrlCheck = oi_remote_program_validate_url(isset($officialUrls[$i]) ? $officialUrls[$i] : '');
    if (!$officialUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / official_url] '.$officialUrlCheck['reason']);
    }
    $officialUrl = $officialUrlCheck['url'];

    $winUrlCheck = oi_remote_program_validate_url(isset($downloadWindows[$i]) ? $downloadWindows[$i] : '');
    if (!$winUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / windows] '.$winUrlCheck['reason']);
    }
    $winUrl = $winUrlCheck['url'];

    $macUrlCheck = oi_remote_program_validate_url(isset($downloadMacos[$i]) ? $downloadMacos[$i] : '');
    if (!$macUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / macos] '.$macUrlCheck['reason']);
    }
    $macUrl = $macUrlCheck['url'];

    $linuxUrlCheck = oi_remote_program_validate_url(isset($downloadLinux[$i]) ? $downloadLinux[$i] : '');
    if (!$linuxUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / linux] '.$linuxUrlCheck['reason']);
    }
    $linuxUrl = $linuxUrlCheck['url'];

    $androidUrlCheck = oi_remote_program_validate_url(isset($downloadAndroid[$i]) ? $downloadAndroid[$i] : '');
    if (!$androidUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / android] '.$androidUrlCheck['reason']);
    }
    $androidUrl = $androidUrlCheck['url'];

    $iosUrlCheck = oi_remote_program_validate_url(isset($downloadIos[$i]) ? $downloadIos[$i] : '');
    if (!$iosUrlCheck['ok']) {
        alert('URL 검증 실패 [row '.($i + 1).' / ios] '.$iosUrlCheck['reason']);
    }
    $iosUrl = $iosUrlCheck['url'];

    $sortOrder = (int)(isset($sortOrders[$i]) ? $sortOrders[$i] : ($i + 1));
    $isActive = isset($rowActive[$i]) ? 1 : 0;

    $programKeySql = sql_escape_string($programKey);
    $programTypeSql = sql_escape_string($programType);
    $nameSql = sql_escape_string($name);
    $aliasesJsonSql = sql_escape_string($aliasesJson);
    $officialUrlSql = sql_escape_string($officialUrl);
    $winUrlSql = sql_escape_string($winUrl);
    $macUrlSql = sql_escape_string($macUrl);
    $linuxUrlSql = sql_escape_string($linuxUrl);
    $androidUrlSql = sql_escape_string($androidUrl);
    $iosUrlSql = sql_escape_string($iosUrl);
    $nowSql = sql_escape_string($now);

    $sql = " INSERT INTO `{$g5['remote_program_catalog_table']}`
                SET program_key = '{$programKeySql}',
                    program_type = '{$programTypeSql}',
                    name = '{$nameSql}',
                    official_url = '{$officialUrlSql}',
                    aliases_json = '{$aliasesJsonSql}',
                    download_windows = '{$winUrlSql}',
                    download_macos = '{$macUrlSql}',
                    download_linux = '{$linuxUrlSql}',
                    download_android = '{$androidUrlSql}',
                    download_ios = '{$iosUrlSql}',
                    sort_order = '{$sortOrder}',
                    is_active = '{$isActive}',
                    created_at = '{$nowSql}',
                    updated_at = '{$nowSql}' ";
    sql_query($sql, false);
    $insertCount++;
}

if ($insertCount < 1) {
    alert('유효한 카탈로그 항목이 없어 저장하지 못했습니다.');
}

if ($viewProgramType === 'remote') {
    alert('원격제어 S/W 카탈로그가 저장되었습니다.');
    goto_url('./remote_program_catalog.php?program_type=remote');
} else if ($viewProgramType === 'vpn') {
    alert('VPN 접속S/W 카탈로그가 저장되었습니다.');
    goto_url('./remote_program_catalog.php?program_type=vpn');
}

alert('원격/VPN 프로그램 카탈로그가 저장되었습니다.');
goto_url('./remote_program_catalog.php');
?>
