<?php
/**
 * 单次访问（Visit）生命周期：一次独立打开 = 一条日志；同 visit 内续步仅 UPDATE。
 */
class VisitorVisitContext
{
    const KEY_LOG_ID    = 'cloak_visit_log_id';
    const KEY_FINALIZED = 'cloak_visit_finalized';
    const KEY_ACTIVE    = 'cloak_visit_active';

    public static function clear()
    {
        unset(
            $_SESSION[self::KEY_LOG_ID],
            $_SESSION[self::KEY_FINALIZED],
            $_SESSION[self::KEY_ACTIVE]
        );
    }

    /**
     * @return int
     */
    public static function currentLogId()
    {
        return (int) ($_SESSION[self::KEY_LOG_ID] ?? 0);
    }

    public static function isFinalized()
    {
        return !empty($_SESSION[self::KEY_FINALIZED]);
    }

    /**
     * ip_check 入口：识别刷新导航并开启新 visit。
     */
    public static function evaluateAtEntry()
    {
        if (self::isFcheckRequest()) {
            return;
        }
        if (self::isRefreshNavigation()) {
            self::clear();
        }
    }

    public static function markVisitActive()
    {
        $_SESSION[self::KEY_ACTIVE] = 1;
    }

    public static function isFcheckRequest()
    {
        $script = $_SERVER['SCRIPT_NAME'] ?? $_SERVER['PHP_SELF'] ?? '';
        return basename($script) === 'f_check.php';
    }

    public static function hasContinuationMarker()
    {
        if (isset($_GET['time']) && (string) $_GET['time'] !== '') {
            return true;
        }
        return self::isFcheckRequest();
    }

    public static function isRefreshNavigation()
    {
        if (self::hasContinuationMarker()) {
            return false;
        }
        if (self::currentLogId() <= 0 || self::isFinalized()) {
            return false;
        }
        $mode = strtolower((string) ($_SERVER['HTTP_SEC_FETCH_MODE'] ?? ''));
        return $mode === 'navigate';
    }

    public static function isNewVisit()
    {
        if (self::isRefreshNavigation()) {
            return true;
        }
        if (self::currentLogId() <= 0) {
            return true;
        }
        if (self::isFinalized()) {
            return true;
        }
        return false;
    }

    public static function isContinuation()
    {
        if (self::isRefreshNavigation()) {
            return false;
        }
        if (self::hasContinuationMarker()) {
            return true;
        }
        if (self::currentLogId() > 0 && !self::isFinalized()) {
            return true;
        }
        if (!empty($_SESSION[self::KEY_ACTIVE]) && self::currentLogId() <= 0) {
            return true;
        }
        return false;
    }

    /**
     * INSERT 前：已 finalize 或刷新后的新 visit 清除旧绑定。
     */
    public static function prepareForNewInsert()
    {
        if (!self::isNewVisit()) {
            return;
        }
        $hadFinalized = self::isFinalized();
        unset($_SESSION[self::KEY_FINALIZED]);
        if ($hadFinalized || self::isRefreshNavigation()) {
            unset($_SESSION[self::KEY_LOG_ID]);
        }
        if (empty($_SESSION[self::KEY_ACTIVE])) {
            self::markVisitActive();
        }
        if (class_exists('VisitorApiAudit', false)) {
            VisitorApiAudit::clearByApi();
        }
    }

    public static function shouldPersistAsUpdate()
    {
        return self::currentLogId() > 0 && !self::isFinalized() && !self::isNewVisit();
    }

    /**
     * @param int $logId
     */
    public static function bindLogId($logId)
    {
        $logId = (int) $logId;
        if ($logId > 0) {
            $_SESSION[self::KEY_LOG_ID] = $logId;
        }
    }

    /**
     * @param string|null $result
     */
    public static function finalizeVisit($result = null)
    {
        $_SESSION[self::KEY_FINALIZED] = 1;
        unset($_SESSION[self::KEY_ACTIVE]);
    }

    /**
     * @param string $result
     */
    public static function shouldFinalizeOnResult($result)
    {
        $r = (string) $result;
        return $r === 'true' || $r === 'false';
    }

    /**
     * @param array $logs
     * @return array
     */
    public static function normalizeLogsForDb(array $logs)
    {
        $result = (string) ($logs['result'] ?? '');
        if (function_exists('cloak_normalize_log_reason')) {
            $logs['reason'] = cloak_normalize_log_reason($result, $logs['reason'] ?? '');
        }
        return $logs;
    }
}
