<?php
/**
 * visitor_logs 表结构升级（新增请求头与判定时长字段）
 */
class VisitorLogSchema
{
    /** @var bool */
    private static $ensured = false;

    /** @var bool */
    private static $indexesEnsured = false;

    /**
     * @param mysqli $conn
     */
    public static function ensureColumns($conn)
    {
        if (self::$ensured) {
            return;
        }
        $columns = [
            'user_agent'          => "ALTER TABLE `visitor_logs` ADD COLUMN `user_agent` TEXT NULL COMMENT 'User-Agent 完整值' AFTER `language`",
            'http_referer'        => "ALTER TABLE `visitor_logs` ADD COLUMN `http_referer` TEXT NULL COMMENT 'HTTP Referer 完整值' AFTER `user_agent`",
            'accept_language_raw' => "ALTER TABLE `visitor_logs` ADD COLUMN `accept_language_raw` TEXT NULL COMMENT 'Accept-Language 完整值' AFTER `http_referer`",
            'judge_timing'        => "ALTER TABLE `visitor_logs` ADD COLUMN `judge_timing` TEXT NULL COMMENT '判定用时 JSON' AFTER `accept_language_raw`",
            'fp_hdata'            => "ALTER TABLE `visitor_logs` ADD COLUMN `fp_hdata` TEXT NULL COMMENT '指纹 hdata 解码 JSON' AFTER `judge_timing`",
            'api_by_request'      => "ALTER TABLE `visitor_logs` ADD COLUMN `api_by_request` TEXT NULL COMMENT 'byApi 请求参数 JSON' AFTER `fp_hdata`",
            'api_by_response'     => "ALTER TABLE `visitor_logs` ADD COLUMN `api_by_response` TEXT NULL COMMENT 'byApi 响应 JSON' AFTER `api_by_request`",
            'api_risk_request'    => "ALTER TABLE `visitor_logs` ADD COLUMN `api_risk_request` TEXT NULL COMMENT 'byApiRisk 请求参数 JSON' AFTER `api_by_response`",
            'api_risk_response'   => "ALTER TABLE `visitor_logs` ADD COLUMN `api_risk_response` TEXT NULL COMMENT 'byApiRisk 响应 JSON' AFTER `api_risk_request`",
            'is_simulation'       => "ALTER TABLE `visitor_logs` ADD COLUMN `is_simulation` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否模拟测试' AFTER `api_risk_response`",
            'sim_source_log_id'   => "ALTER TABLE `visitor_logs` ADD COLUMN `sim_source_log_id` INT UNSIGNED NULL COMMENT '模拟重放来源日志 ID' AFTER `is_simulation`",
        ];
        foreach ($columns as $name => $ddl) {
            if (!self::columnExists($conn, 'visitor_logs', $name)) {
                @$conn->query($ddl);
            }
        }
        self::$ensured = true;
    }

    /**
     * @param mysqli $conn
     */
    public static function ensureIndexes($conn)
    {
        if (self::$indexesEnsured) {
            return;
        }
        $indexes = [
            'idx_visit_date'  => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_visit_date` (`visit_date`)',
            'idx_result'      => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_result` (`result`)',
            'idx_domain_date' => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_domain_date` (`domain`, `visit_date`)',
            'idx_country'     => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_country` (`country`)',
            'idx_ip_domain'   => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_ip_domain` (`IP`, `domain`)',
        ];
        foreach ($indexes as $name => $ddl) {
            if (!self::indexExists($conn, 'visitor_logs', $name)) {
                @$conn->query($ddl);
            }
        }
        self::$indexesEnsured = true;
    }

    /**
     * @param mysqli $conn
     * @param string $table
     * @param string $indexName
     */
    private static function indexExists($conn, $table, $indexName)
    {
        $tableEsc = cloak_db_escape($conn, $table);
        $indexEsc = cloak_db_escape($conn, $indexName);
        $sql      = "SHOW INDEX FROM `{$tableEsc}` WHERE Key_name = '{$indexEsc}'";
        if ($res = $conn->query($sql)) {
            $exists = $res->num_rows > 0;
            $res->free();
            return $exists;
        }
        return false;
    }

    /**
     * @param mysqli $conn
     * @param string $table
     * @param string $column
     */
    private static function columnExists($conn, $table, $column)
    {
        $tableEsc  = cloak_db_escape($conn, $table);
        $columnEsc = cloak_db_escape($conn, $column);
        $sql       = "SHOW COLUMNS FROM `{$tableEsc}` LIKE '{$columnEsc}'";
        if ($res = $conn->query($sql)) {
            $exists = $res->num_rows > 0;
            $res->free();
            return $exists;
        }
        return false;
    }
}
