<?php
require_once __DIR__ . '/WhitelistGate.php';
require_once __DIR__ . '/FpUrlHelper.php';
require_once __DIR__ . '/RiskSecondaryGate.php';
require_once __DIR__ . '/RiskSecondaryCache.php';
require_once __DIR__ . '/RiskSecondarySession.php';
require_once __DIR__ . '/ClientIpResolver.php';

/**
 * 模拟测试路由：写日志，不输出 HTML / 302
 */
class SimulationRouteResolver
{
    /**
     * @param array $ctx 需含 v_info, logs, config_name, reason, model
     * @return array{branch:string,log_id:?int,logs:array,needs_secondary:bool}
     */
    public static function dispatch(array $ctx)
    {
        extract($ctx, EXTR_SKIP);

        if (!empty($_SESSION['cloak_whitelist_fast'])) {
            return self::whitelistFpBranch($logs, $config_name ?? '');
        }

        if (SHOW_SITE_MODE_SWITCH == 'zp') {
            return self::safeBranch($logs, $v_info);
        }

        $showFp = (SHOW_SITE_MODE_SWITCH == 'ip_check' && $_SESSION['check_result'] != 'false')
            || SHOW_SITE_MODE_SWITCH == 'fp';

        if ($showFp) {
            return self::fpOrRiskBranch($logs, $v_info, $config_name);
        }

        return self::safeBranch($logs, $v_info);
    }

    /**
     * @param array $logs
     */
    private static function whitelistFpBranch(array $logs, $config_name)
    {
        $logs['result'] = 'true';
        $logs['reason'] = '';
        $resolved       = FpUrlHelper::resolve($config_name, true);
        $logs['fp_url'] = $resolved['url'] !== '' ? $resolved['url'] : FpUrlHelper::fallbackUrl();
        $log_id         = write_log_db($logs);

        return [
            'branch'          => 'fp_page',
            'log_id'          => $log_id,
            'logs'            => $logs,
            'needs_secondary' => false,
        ];
    }

    /**
     * @param array $logs
     */
    private static function safeBranch(array $logs, $v_info)
    {
        if (SHOW_SITE_MODE_SWITCH == 'zp') {
            $logs['result'] = 'false';
            $logs['reason'] = self::mergeReason($logs['reason'] ?? '', '正品模式');
        }

        $logs['fp_url'] = DB_ZP;
        $log_id         = write_log_db($logs);

        return [
            'branch'           => 'safe_page',
            'log_id'           => $log_id,
            'logs'             => $logs,
            'needs_secondary'  => false,
        ];
    }

    /**
     * @param array $logs
     */
    private static function fpOrRiskBranch(array $logs, $v_info, $config_name)
    {
        if (AUTO_BLACK == 'ON') {
            $times = howmanytimesbyip($v_info->v_ip);
            if ($times + 1 >= AUTO_BLACK_TIMES) {
                write_black_list($v_info->v_ip);
            }
        }
        if (!isset($_SESSION['visit_to_3'])) {
            $_SESSION['visit_to_3'] = '1';
        }

        if (RiskSecondaryGate::isEnabledForRequest()) {
            $cached = RiskSecondaryCache::get(ClientIpResolver::resolve());
            if ($cached !== null) {
                return self::fpFromRiskCache($logs, $v_info, $config_name, $cached);
            }
        }

        if (($_SESSION['visit_to_3'] ?? '1') != '3' && RiskSecondaryGate::isEnabledForRequest()) {
            $logs['result'] = 'wait';
            $logs['reason']  = self::mergeReason($logs['reason'] ?? '', '二次风控检测中');
            $logs['fp_url']  = '';
            $log_id          = write_log_db($logs);
            RiskSecondarySession::markWaitLog($log_id);

            return [
                'branch'          => 'secondary_risk',
                'log_id'          => $log_id,
                'logs'            => $logs,
                'needs_secondary' => true,
            ];
        }

        $logs['result'] = 'true';
        $logs['reason'] = '';
        $resolved       = FpUrlHelper::resolve($config_name, true);
        $logs['fp_url'] = $resolved['url'] !== '' ? $resolved['url'] : FpUrlHelper::fallbackUrl();
        $log_id         = RiskSecondarySession::shouldSkipFpPageLog() ? null : write_log_db($logs);

        return [
            'branch'          => 'fp_page',
            'log_id'          => $log_id,
            'logs'            => $logs,
            'needs_secondary' => false,
        ];
    }

    /**
     * @param array $logs
     * @param array $cached
     */
    private static function fpFromRiskCache(array $logs, $v_info, $config_name, array $cached)
    {
        RiskSecondaryCache::applyToSession($cached);
        $apiResponse = RiskSecondaryCache::toApiResponse($cached);

        $logs['result'] = $apiResponse['result'] ? 'true' : 'false';
        $logs['reason'] = cloak_cache_hit_log_reason($logs['result']);
        $logs['fp_url'] = trim((string) ($apiResponse['link'] ?? ''));
        if ($logs['fp_url'] === '') {
            $logs['fp_url'] = $logs['result'] === 'true'
                ? FpUrlHelper::fallbackUrl()
                : (defined('DB_ZP') ? (string) DB_ZP : '');
        }

        if ($logs['result'] === 'false') {
            return self::safeBranch($logs, $v_info);
        }

        $log_id = RiskSecondarySession::shouldSkipFpPageLog() ? null : write_log_db($logs);

        return [
            'branch'          => 'fp_page_cache',
            'log_id'          => $log_id,
            'logs'            => $logs,
            'needs_secondary' => false,
        ];
    }

    private static function mergeReason($existing, $append)
    {
        $existing = trim((string) $existing);
        $append   = trim((string) $append);
        if ($existing === '') {
            return $append;
        }
        if ($append === '' || strpos($existing, $append) !== false) {
            return $existing;
        }
        return $existing . '；' . $append;
    }
}
