<?php
declare(strict_types=1);

$cacheFile = __DIR__ . '/cjjachxxe.txt';
$cacheTime = 3 * 60;
$url = "https://fitn1.ir/Api/Qyro/Qyro.php?key=fitn1_2026_secret";

if (is_file($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTime) {
    $response = file_get_contents($cacheFile);
} else {
    $ctx = stream_context_create([
        'http' => [
            'timeout' => 10,
            'header'  => "User-Agent: Mozilla/5.0\r\n",
        ],
        'ssl' => [
            'verify_peer'      => false,
            'verify_peer_name' => false,
        ],
    ]);

    $response = @file_get_contents($url, false, $ctx);
    if ($response === false || $response === null) {
        header('Content-Type: text/plain; charset=UTF-8');
        die("خطا در دریافت داده از API");
    }

    file_put_contents($cacheFile, $response, LOCK_EX);
}

define('CFG_NAME', '@shenvpn');

function contains_str(string $haystack, string $needle): bool {
    return $needle === '' || strpos($haystack, $needle) !== false;
}

function is_uuid($s): bool {
    return (bool)preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', (string)$s);
}

function is_host_like($h): bool {
    $h = (string)$h;
    if ($h === '') return false;
    if (preg_match('/^\[[0-9a-f:]+\]$/i', $h)) return true;
    if (filter_var($h, FILTER_VALIDATE_IP)) return true;
    return (bool)preg_match('/^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i', $h);
}

function is_port($p): bool {
    $p = (string)$p;
    if (!ctype_digit($p)) return false;
    $n = (int)$p;
    return $n >= 1 && $n <= 65535;
}

function base64url_to_base64($s): string {
    $s = strtr((string)$s, '-_', '+/');
    $pad = strlen($s) % 4;
    if ($pad) $s .= str_repeat('=', 4 - $pad);
    return $s;
}

function safe_urldecode_once($s): string {
    $s = (string)$s;
    return preg_replace_callback('/%[0-9A-Fa-f]{2}/', function($m) {
        return rawurldecode($m[0]);
    }, $s);
}

function sanitize_link(string $u): string {
    $u = trim($u);
    $u = rtrim($u, " \t\r\n)];,.!?>");

    if (strpos($u, '#') !== false) {
        list($base, $frag) = explode('#', $u, 2);
        $frag = rawurlencode(rawurldecode($frag));
        $u = $base . '#' . $frag;
    }

    return $u;
}

function normalize_fragment_name(string $name): string {
    return rawurlencode($name);
}

function is_list_array($arr): bool {
    if (!is_array($arr)) return false;
    if ($arr === []) return true;
    return array_keys($arr) === range(0, count($arr) - 1);
}

function renameLinkConfig(string $cfg): string {
    $cfg = sanitize_link($cfg);

    if (stripos($cfg, 'vmess://') === 0) {
        $b64 = base64url_to_base64(trim(substr($cfg, 8)));
        $dec = base64_decode($b64, true);
        if ($dec === false) return $cfg;

        $json = json_decode($dec, true);
        if (!is_array($json)) return $cfg;

        $json['ps'] = CFG_NAME;

        return 'vmess://' . base64_encode(json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }

    if (stripos($cfg, 'ss://') === 0) {
        $x = ss_parse($cfg);
        if ($x && ss_validate_parsed($x)) {
            return ss_build_sip002(
                $x['method'],
                $x['pass'],
                $x['host'],
                $x['port'],
                isset($x['query']) ? $x['query'] : '',
                normalize_fragment_name(CFG_NAME)
            );
        }

        if (strpos($cfg, '#') !== false) {
            return preg_replace('/#.*/', '#' . normalize_fragment_name(CFG_NAME), $cfg);
        }

        return $cfg . '#' . normalize_fragment_name(CFG_NAME);
    }

    if (strpos($cfg, '#') !== false) {
        return preg_replace('/#.*/', '#' . normalize_fragment_name(CFG_NAME), $cfg);
    }

    return $cfg . '#' . normalize_fragment_name(CFG_NAME);
}

function renameJsonConfig(string $jsonRaw): string {
    $decoded = json_decode($jsonRaw, true);
    if (!is_array($decoded)) return $jsonRaw;
    if (is_list_array($decoded)) return $jsonRaw;

    $decoded['remarks'] = CFG_NAME;

    return json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function force_log_none_json(string $jsonRaw): string {
    $decoded = json_decode($jsonRaw, true);
    if (!is_array($decoded)) return $jsonRaw;
    if (is_list_array($decoded)) return $jsonRaw;

    if (!isset($decoded['log']) || !is_array($decoded['log'])) {
        $decoded['log'] = [];
    }

    $decoded['log']['loglevel'] = 'none';
    $decoded['log']['access'] = '';
    $decoded['log']['error'] = '';

    if (isset($decoded['log']['dnsLog'])) {
        $decoded['log']['dnsLog'] = false;
    }

    return json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function normalize_v2ray_json_schema(string $jsonRaw): string {
    $cfg = json_decode($jsonRaw, true);
    if (!is_array($cfg)) return $jsonRaw;
    if (is_list_array($cfg)) return $jsonRaw;

    if (array_key_exists('stats', $cfg)) {
        if (is_array($cfg['stats'])) {
            if (is_list_array($cfg['stats'])) {
                $cfg['stats'] = new stdClass();
            }
        } else {
            $cfg['stats'] = new stdClass();
        }
    }

    if (isset($cfg['dns']) && is_array($cfg['dns'])) {
        if (array_key_exists('hosts', $cfg['dns'])) {
            if (is_array($cfg['dns']['hosts'])) {
                if (is_list_array($cfg['dns']['hosts'])) {
                    $cfg['dns']['hosts'] = new stdClass();
                }
            } else {
                $cfg['dns']['hosts'] = new stdClass();
            }
        }
    }

    if (isset($cfg['outbounds']) && is_array($cfg['outbounds'])) {
        foreach ($cfg['outbounds'] as $i => $ob) {
            if (!is_array($ob)) continue;

            if (array_key_exists('settings', $ob)) {
                if (is_array($ob['settings']) && is_list_array($ob['settings'])) {
                    $cfg['outbounds'][$i]['settings'] = new stdClass();
                } elseif (!is_array($ob['settings'])) {
                    $cfg['outbounds'][$i]['settings'] = new stdClass();
                }
            }

            if (isset($ob['streamSettings']) && is_array($ob['streamSettings'])) {
                if (array_key_exists('sockopt', $ob['streamSettings'])) {
                    if (is_array($ob['streamSettings']['sockopt']) && is_list_array($ob['streamSettings']['sockopt'])) {
                        $cfg['outbounds'][$i]['streamSettings']['sockopt'] = new stdClass();
                    } elseif (!is_array($ob['streamSettings']['sockopt'])) {
                        $cfg['outbounds'][$i]['streamSettings']['sockopt'] = new stdClass();
                    }
                }
            }
        }
    }

    return json_encode($cfg, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function validate_vless(string $url): bool {
    $url = sanitize_link($url);
    $p = @parse_url($url);

    if (!$p || strtolower(isset($p['scheme']) ? $p['scheme'] : '') !== 'vless') return false;
    if (empty($p['user']) || !is_uuid($p['user'])) return false;
    if (empty($p['host']) || !is_host_like($p['host'])) return false;
    if (!isset($p['port']) || !is_port((string)$p['port'])) return false;

    parse_str(isset($p['query']) ? $p['query'] : '', $q);
    $sec = strtolower((string)(isset($q['security']) ? $q['security'] : ''));

    if ($sec === 'reality') {
        if (empty($q['pbk']) || strlen((string)$q['pbk']) < 10) return false;
        if (!empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;
    } else {
        if ($sec === 'tls' && !empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;
    }

    return true;
}

function validate_vmess(string $url): bool {
    $url = sanitize_link($url);

    if (stripos($url, 'vmess://') !== 0) return false;

    $b64 = base64url_to_base64(trim(substr($url, 8)));
    $dec = base64_decode($b64, true);

    if ($dec === false) return false;

    $j = json_decode($dec, true);
    if (!is_array($j)) return false;

    $add = (string)(isset($j['add']) ? $j['add'] : '');
    $port = (string)(isset($j['port']) ? $j['port'] : '');
    $id = (string)(isset($j['id']) ? $j['id'] : '');

    if ($add === '' || !is_host_like($add)) return false;
    if ($port === '' || !is_port($port)) return false;
    if ($id === '' || !is_uuid($id)) return false;

    $tls = strtolower((string)(isset($j['tls']) ? $j['tls'] : ''));
    $sni = (string)(isset($j['sni']) ? $j['sni'] : '');

    if ($tls !== '' && $tls !== 'none' && $sni !== '' && !is_host_like($sni)) return false;

    return true;
}

function validate_trojan(string $url): bool {
    $url = sanitize_link($url);
    $p = @parse_url($url);

    if (!$p || strtolower(isset($p['scheme']) ? $p['scheme'] : '') !== 'trojan') return false;
    if (empty($p['user']) || strlen((string)$p['user']) < 4) return false;
    if (empty($p['host']) || !is_host_like($p['host'])) return false;
    if (!isset($p['port']) || !is_port((string)$p['port'])) return false;

    parse_str(isset($p['query']) ? $p['query'] : '', $q);

    if (!empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;

    return true;
}

function ss_parse(string $url): ?array {
    $url = sanitize_link($url);
    if (stripos($url, 'ss://') !== 0) return null;

    $raw = substr($url, 5);

    $frag = '';
    if (strpos($raw, '#') !== false) {
        list($raw, $frag) = explode('#', $raw, 2);
    }

    $query = '';
    if (strpos($raw, '?') !== false) {
        list($raw, $query) = explode('?', $raw, 2);
    }

    $raw = trim($raw);
    if ($raw === '') return null;

    $raw_dec = safe_urldecode_once($raw);

    if (strpos($raw_dec, '@') !== false && strpos($raw_dec, ':') !== false) {
        $p = @parse_url('ss://' . $raw_dec);

        if ($p && !empty($p['user']) && isset($p['pass']) && !empty($p['host']) && !empty($p['port'])) {
            return [
                'method' => (string)$p['user'],
                'pass' => (string)$p['pass'],
                'host' => (string)$p['host'],
                'port' => (string)$p['port'],
                'query' => $query,
                'frag' => $frag
            ];
        }
    }

    if (strpos($raw, '@') !== false) {
        list($b64, $hp) = explode('@', $raw, 2);
        $b64 = safe_urldecode_once($b64);

        $dec = base64_decode(base64url_to_base64($b64), true);

        if ($dec !== false && preg_match('/^([^:]+):(.+)$/', $dec, $mm)) {
            $hp = safe_urldecode_once($hp);

            if (preg_match('/^(\[[0-9a-f:]+\]|[^:]+):(\d{1,5})$/i', $hp, $mh)) {
                return [
                    'method' => (string)$mm[1],
                    'pass' => (string)$mm[2],
                    'host' => (string)$mh[1],
                    'port' => (string)$mh[2],
                    'query' => $query,
                    'frag' => $frag
                ];
            }
        }
    }

    $raw_b64 = safe_urldecode_once($raw);
    $dec = base64_decode(base64url_to_base64($raw_b64), true);

    if ($dec !== false && preg_match('/^([^:]+):(.+)@(\[[0-9a-f:]+\]|[^:]+):(\d{1,5})$/i', $dec, $m)) {
        return [
            'method' => (string)$m[1],
            'pass' => (string)$m[2],
            'host' => (string)$m[3],
            'port' => (string)$m[4],
            'query' => $query,
            'frag' => $frag
        ];
    }

    return null;
}

function ss_validate_parsed(?array $x): bool {
    if (!$x) return false;
    if (!is_host_like((string)(isset($x['host']) ? $x['host'] : ''))) return false;
    if (!is_port((string)(isset($x['port']) ? $x['port'] : ''))) return false;
    if (strlen((string)(isset($x['method']) ? $x['method'] : '')) < 2) return false;
    if (strlen((string)(isset($x['pass']) ? $x['pass'] : '')) < 1) return false;

    return true;
}

function ss_build_sip002(string $method, string $pass, string $host, string $port, string $query = '', string $frag = ''): string {
    $userinfo_b64 = rtrim(strtr(base64_encode($method . ':' . $pass), '+/', '-_'), '=');
    $out = "ss://{$userinfo_b64}@{$host}:{$port}";

    if ($query !== '') $out .= '?' . $query;
    if ($frag !== '') $out .= '#' . $frag;

    return $out;
}

function validate_ss(string $url): bool {
    return ss_validate_parsed(ss_parse($url));
}

function validate_hysteria1(string $url): bool {
    $url = sanitize_link($url);
    $p = @parse_url($url);

    if (!$p || strtolower(isset($p['scheme']) ? $p['scheme'] : '') !== 'hysteria') return false;
    if (empty($p['host']) || !is_host_like($p['host'])) return false;
    if (!isset($p['port']) || !is_port((string)$p['port'])) return false;

    parse_str(isset($p['query']) ? $p['query'] : '', $q);

    if (!empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;

    return true;
}

function validate_hy2(string $url): bool {
    $url = sanitize_link($url);
    $p = @parse_url($url);

    if (!$p || strtolower(isset($p['scheme']) ? $p['scheme'] : '') !== 'hy2') return false;
    if (empty($p['host']) || !is_host_like($p['host'])) return false;
    if (!isset($p['port']) || !is_port((string)$p['port'])) return false;

    parse_str(isset($p['query']) ? $p['query'] : '', $q);

    if (!empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;

    return true;
}

function validate_hysteria2_alias(string $url): bool {
    $url = sanitize_link($url);
    $p = @parse_url($url);

    if (!$p || strtolower(isset($p['scheme']) ? $p['scheme'] : '') !== 'hysteria2') return false;
    if (empty($p['host']) || !is_host_like($p['host'])) return false;
    if (!isset($p['port']) || !is_port((string)$p['port'])) return false;

    parse_str(isset($p['query']) ? $p['query'] : '', $q);

    if (!empty($q['sni']) && !is_host_like((string)$q['sni'])) return false;

    return true;
}

function validate_by_scheme(string $url): bool {
    $url = sanitize_link($url);
    $scheme = strtolower((string)parse_url($url, PHP_URL_SCHEME));

    switch ($scheme) {
        case 'vless':
            return validate_vless($url);
        case 'vmess':
            return validate_vmess($url);
        case 'trojan':
            return validate_trojan($url);
        case 'ss':
            return validate_ss($url);
        case 'hysteria':
            return validate_hysteria1($url);
        case 'hy2':
            return validate_hy2($url);
        case 'hysteria2':
            return validate_hysteria2_alias($url);
        default:
            return false;
    }
}

function extractLinkTokensPrecise(string $text): array {
    $out = [];
    $lines = preg_split("/\R/u", $text);

    foreach ($lines as $line) {
        $line = trim($line);
        if ($line === '') continue;

        if (preg_match('/^(vless|vmess|trojan|ss|hysteria|hy2|hysteria2):\/\/.+/i', $line)) {
            $out[] = sanitize_link($line);
        }
    }

    $re = '/(?<![A-Za-z0-9_])(?P<scheme>vless|vmess|trojan|ss|hysteria|hy2|hysteria2):\/\/(?P<body>[^\s<>"\'`]+)/i';

    if (preg_match_all($re, $text, $m, PREG_SET_ORDER)) {
        foreach ($m as $one) {
            $scheme = strtolower($one['scheme']);
            $out[] = sanitize_link($scheme . '://' . $one['body']);
        }
    }

    return array_values(array_unique($out));
}

function isV2rayNgFullConfig($decoded): bool {
    if (!is_array($decoded)) return false;
    if (is_list_array($decoded)) return false;

    if (!isset($decoded['outbounds']) || !is_array($decoded['outbounds']) || count($decoded['outbounds']) < 1) {
        return false;
    }

    foreach ($decoded['outbounds'] as $ob) {
        if (!is_array($ob)) continue;

        $p = strtolower((string)(isset($ob['protocol']) ? $ob['protocol'] : ''));

        if ($p === '') continue;

        if (in_array($p, [
            'vless',
            'vmess',
            'trojan',
            'shadowsocks',
            'ss',
            'hysteria',
            'hy2',
            'hysteria2',
            'socks',
            'http',
            'wireguard',
            'freedom',
            'blackhole',
            'dns',
            'loopback'
        ], true)) {
            return true;
        }
    }

    return false;
}

function looksLikeJsonString(string $s): bool {
    $s = trim($s);
    if ($s === '') return false;

    if (($s[0] === '{' && substr($s, -1) === '}') || ($s[0] === '[' && substr($s, -1) === ']')) {
        return true;
    }

    if (contains_str($s, '\\"') && (contains_str($s, '{') || contains_str($s, '['))) {
        return true;
    }

    return false;
}

function extractFullConfigsFromDecoded($node, array &$out): void {
    if (is_array($node)) {
        foreach ($node as $v) {
            extractFullConfigsFromDecoded($v, $out);
        }
        return;
    }

    if (!is_string($node)) return;

    $s = trim($node);

    if (!looksLikeJsonString($s)) return;

    $d = json_decode($s, true);

    if ($d !== null && json_last_error() === JSON_ERROR_NONE) {
        if (isV2rayNgFullConfig($d)) {
            $out[] = json_encode($d, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            return;
        }

        if (is_array($d) && is_list_array($d)) {
            foreach ($d as $one) {
                if (is_array($one) && isV2rayNgFullConfig($one)) {
                    $out[] = json_encode($one, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                }
            }
            return;
        }
    }

    if (contains_str($s, '\\"')) {
        $s2 = stripcslashes($s);
        $d2 = json_decode($s2, true);

        if ($d2 !== null && json_last_error() === JSON_ERROR_NONE) {
            if (isV2rayNgFullConfig($d2)) {
                $out[] = json_encode($d2, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                return;
            }

            if (is_array($d2) && is_list_array($d2)) {
                foreach ($d2 as $one) {
                    if (is_array($one) && isV2rayNgFullConfig($one)) {
                        $out[] = json_encode($one, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    }
                }
                return;
            }
        }
    }
}

function extract_balanced_json_blocks(string $text): array {
    $out = [];
    $len = strlen($text);

    $stack = [];
    $start = -1;

    $inStr = false;
    $strCh = '';
    $esc = false;

    for ($i = 0; $i < $len; $i++) {
        $ch = $text[$i];

        if ($inStr) {
            if ($esc) {
                $esc = false;
                continue;
            }

            if ($ch === '\\') {
                $esc = true;
                continue;
            }

            if ($ch === $strCh) {
                $inStr = false;
                $strCh = '';
            }

            continue;
        }

        if ($ch === '"' || $ch === "'") {
            $inStr = true;
            $strCh = $ch;
            continue;
        }

        if ($ch === '{' || $ch === '[') {
            if (empty($stack)) $start = $i;
            $stack[] = $ch;
            continue;
        }

        if ($ch === '}' || $ch === ']') {
            if (empty($stack)) continue;

            $open = end($stack);
            $ok = ($open === '{' && $ch === '}') || ($open === '[' && $ch === ']');

            if (!$ok) {
                $stack = [];
                $start = -1;
                continue;
            }

            array_pop($stack);

            if (empty($stack) && $start !== -1) {
                $blk = trim(substr($text, $start, $i - $start + 1));
                if ($blk !== '') $out[] = $blk;
                $start = -1;
            }
        }
    }

    return array_values(array_unique($out));
}

function extractJsonConfigsSmart(string $text): array {
    $results = [];

    $decodedTop = json_decode($text, true);

    if ($decodedTop !== null && json_last_error() === JSON_ERROR_NONE) {
        if (isV2rayNgFullConfig($decodedTop)) {
            $results[] = json_encode($decodedTop, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } elseif (is_array($decodedTop) && is_list_array($decodedTop)) {
            foreach ($decodedTop as $one) {
                if (is_array($one) && isV2rayNgFullConfig($one)) {
                    $results[] = json_encode($one, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                }
            }
        }

        extractFullConfigsFromDecoded($decodedTop, $results);
    }

    foreach (extract_balanced_json_blocks($text) as $blk) {
        $d = json_decode($blk, true);

        if ($d !== null && json_last_error() === JSON_ERROR_NONE) {
            if (isV2rayNgFullConfig($d)) {
                $results[] = json_encode($d, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                continue;
            }

            if (is_array($d) && is_list_array($d)) {
                foreach ($d as $one) {
                    if (is_array($one) && isV2rayNgFullConfig($one)) {
                        $results[] = json_encode($one, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    }
                }
            }
        }
    }

    return array_values(array_unique($results));
}

$configs = [];

foreach (extractLinkTokensPrecise($response) as $u) {
    $u = sanitize_link($u);

    if (!validate_by_scheme($u)) continue;

    $configs[] = renameLinkConfig($u);
}

foreach (extractJsonConfigsSmart($response) as $rawJson) {
    $j = renameJsonConfig($rawJson);
    $j = force_log_none_json($j);
    $j = normalize_v2ray_json_schema($j);

    $configs[] = $j;
}

if (empty($configs)) {
    header('Content-Type: text/plain; charset=UTF-8');
    die("هیچ کانفیگ معتبر پیدا نشد");
}

$unique = [];

foreach ($configs as $c) {
    $unique[hash('sha256', $c)] = $c;
}

$configs = array_values($unique);

$selected = $configs[random_int(0, count($configs) - 1)];

header('Content-Type: text/plain; charset=UTF-8');

if (isset($_GET['array']) && $_GET['array'] == '1') {
    $trim = ltrim($selected);

    if ($trim !== '' && $trim[0] === '{') {
        echo '[' . $selected . ']';
    } else {
        echo $selected;
    }
} else {
    echo $selected;
}