<?php
/**
 * MJ Marketplace v3.0.4.2.8 Auto Repair + Debug + Error Logging
 * Safe schema repair only. It does not rewrite PHP files on live site.
 */
if (!defined('MJ428_AUTO_REPAIR_LOADED')) { define('MJ428_AUTO_REPAIR_LOADED', true); }

if (!function_exists('mj428_now')) { function mj428_now(): string { return date('Y-m-d H:i:s'); } }

if (!function_exists('mj428_safe_scalar')) {
function mj428_safe_scalar($value, int $max = 255): string {
    if (is_array($value) || is_object($value)) { $value = json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); }
    return mb_substr(trim((string)$value), 0, $max);
}}

if (!function_exists('mj428_table_exists')) {
function mj428_table_exists(string $table): bool {
    try { $r = one('SELECT COUNT(*) c FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?', [$table]); return (int)($r['c'] ?? 0) > 0; }
    catch (Throwable $e) { return false; }
}}

if (!function_exists('mj428_column_exists')) {
function mj428_column_exists(string $table, string $column): bool {
    try { $r = one('SELECT COUNT(*) c FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?', [$table,$column]); return (int)($r['c'] ?? 0) > 0; }
    catch (Throwable $e) { return false; }
}}

if (!function_exists('mj428_setting_bool')) {
function mj428_setting_bool(string $key, bool $default = false): bool {
    try {
        if (function_exists('setting')) { $v = strtolower((string)setting($key, $default ? '1' : '0')); }
        else { $v = $default ? '1' : '0'; }
        return in_array($v, ['1','yes','true','on','enabled'], true);
    } catch (Throwable $e) { return $default; }
}}

if (!function_exists('mj428_admin_can_debug')) {
function mj428_admin_can_debug(): bool {
    try {
        if (empty($_SESSION['admin_id'])) { return false; }
        if (!mj428_setting_bool('debug_mode', false)) { return false; }
        if (function_exists('current_admin')) {
            $a = current_admin();
            if (!$a) { return false; }
            $role = strtolower((string)($a['role'] ?? ''));
            return in_array($role, ['super_admin','admin','developer'], true) || !empty($a['is_super_admin']);
        }
        return true;
    } catch (Throwable $e) { return false; }
}}

if (!function_exists('mj428_ensure_ob_buffer')) {
function mj428_ensure_ob_buffer(): void { if (!ob_get_level()) { @ob_start(); } }
}

if (!function_exists('mj428_ensure_schema')) {
function mj428_ensure_schema(): void {
    static $done = false; if ($done) { return; } $done = true;
    try { q("CREATE TABLE IF NOT EXISTS mj_error_logs (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        error_hash CHAR(64) NULL,
        error_type VARCHAR(80) NOT NULL DEFAULT 'runtime',
        severity VARCHAR(30) NOT NULL DEFAULT 'error',
        message LONGTEXT NULL,
        file_path VARCHAR(500) NULL,
        line_number INT NULL,
        sql_text LONGTEXT NULL,
        request_uri VARCHAR(500) NULL,
        user_type VARCHAR(30) NULL,
        user_id BIGINT UNSIGNED NULL,
        ip_address VARCHAR(80) NULL,
        user_agent VARCHAR(255) NULL,
        stack_trace LONGTEXT NULL,
        is_resolved TINYINT(1) NOT NULL DEFAULT 0,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_type_created(error_type, created_at),
        INDEX idx_severity(severity),
        INDEX idx_hash(error_hash),
        INDEX idx_resolved(is_resolved)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("CREATE TABLE IF NOT EXISTS mj_auto_repair_logs (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        repair_key VARCHAR(160) NULL,
        repair_type VARCHAR(80) NOT NULL,
        status VARCHAR(40) NOT NULL DEFAULT 'completed',
        message VARCHAR(255) NULL,
        sql_text LONGTEXT NULL,
        triggered_by VARCHAR(80) NULL,
        request_uri VARCHAR(500) NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_repair_created(repair_type, created_at),
        INDEX idx_status(status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("CREATE TABLE IF NOT EXISTS mj_page_cache (
        cache_key VARCHAR(180) PRIMARY KEY,
        cache_group VARCHAR(80) NOT NULL DEFAULT 'page',
        cache_value LONGTEXT NULL,
        expires_at DATETIME NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME NULL,
        INDEX idx_group_expiry(cache_group, expires_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("CREATE TABLE IF NOT EXISTS mj_count_cache (
        cache_key VARCHAR(180) PRIMARY KEY,
        cache_group VARCHAR(80) NOT NULL DEFAULT 'count',
        cache_value BIGINT NOT NULL DEFAULT 0,
        expires_at DATETIME NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME NULL,
        INDEX idx_group_expiry(cache_group, expires_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("CREATE TABLE IF NOT EXISTS mj_performance_log (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        event_type VARCHAR(80) NOT NULL,
        duration_ms INT NULL,
        request_uri VARCHAR(500) NULL,
        meta_json LONGTEXT NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_event_created(event_type, created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("CREATE TABLE IF NOT EXISTS mj_schema_migrations (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        version VARCHAR(40) NOT NULL UNIQUE,
        migration_file VARCHAR(255) NULL,
        status VARCHAR(40) NOT NULL DEFAULT 'completed',
        started_at DATETIME NULL,
        completed_at DATETIME NULL,
        error_message TEXT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Throwable $e) {}

    try { q("INSERT INTO mj_settings(setting_key,setting_value) VALUES
        ('debug_mode','0'),
        ('auto_repair_enabled','1'),
        ('popup_messages_enabled','1'),
        ('page_speed_mode','1'),
        ('slow_query_log_ms','1200')
        ON DUPLICATE KEY UPDATE setting_value=setting_value"); } catch (Throwable $e) {}
}}

if (!function_exists('mj428_log_error')) {
function mj428_log_error(Throwable $e, string $type = 'runtime', string $sql = '', string $severity = 'error'): int {
    try {
        mj428_ensure_schema();
        $ut = 'guest'; $uid = 0;
        if (!empty($_SESSION['admin_id'])) { $ut = 'admin'; $uid = (int)$_SESSION['admin_id']; }
        elseif (!empty($_SESSION['user_id'])) { $ut = 'user'; $uid = (int)$_SESSION['user_id']; }
        $hash = hash('sha256', $type.'|'.$e->getMessage().'|'.$e->getFile().'|'.$e->getLine().'|'.mb_substr($sql,0,1000));
        q('INSERT INTO mj_error_logs(error_hash,error_type,severity,message,file_path,line_number,sql_text,request_uri,user_type,user_id,ip_address,user_agent,stack_trace,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())', [
            $hash,$type,$severity,$e->getMessage(),$e->getFile(),$e->getLine(),$sql,
            mj428_safe_scalar($_SERVER['REQUEST_URI'] ?? '',500),$ut,$uid,
            mj428_safe_scalar($_SERVER['REMOTE_ADDR'] ?? '',80),mj428_safe_scalar($_SERVER['HTTP_USER_AGENT'] ?? '',255),$e->getTraceAsString()
        ]);
        return (int)db()->lastInsertId();
    } catch (Throwable $ignore) {
        error_log('[MJ Error Log Failed] '.$e->getMessage());
        return 0;
    }
}}

if (!function_exists('mj428_repair_log')) {
function mj428_repair_log(string $type, string $status, string $message, string $sql = '', string $key = ''): void {
    try {
        mj428_ensure_schema();
        q('INSERT INTO mj_auto_repair_logs(repair_key,repair_type,status,message,sql_text,triggered_by,request_uri,created_at) VALUES(?,?,?,?,?,?,?,NOW())', [
            $key,$type,$status,mj428_safe_scalar($message,255),$sql,!empty($_SESSION['admin_id'])?'admin':'system',mj428_safe_scalar($_SERVER['REQUEST_URI'] ?? '',500)
        ]);
    } catch (Throwable $e) {}
}}

if (!function_exists('mj428_repair_columns')) {
function mj428_repair_columns(): int {
    $repairs = [
        ['mj_companies','approved_at','DATETIME NULL'], ['mj_companies','approved_by','INT NULL'], ['mj_companies','verification_status',"VARCHAR(40) NOT NULL DEFAULT 'unverified'"], ['mj_companies','rejection_reason','TEXT NULL'], ['mj_companies','admin_note','TEXT NULL'],
        ['mj_listings','approved_at','DATETIME NULL'], ['mj_listings','approved_by','INT NULL'], ['mj_listings','admin_note','TEXT NULL'], ['mj_listings','rejection_reason','TEXT NULL'],
        ['mj_deals','approved_at','DATETIME NULL'], ['mj_deals','approved_by','INT NULL'], ['mj_deals','admin_note','TEXT NULL'], ['mj_deals','rejection_reason','TEXT NULL'], ['mj_deals','seller_user_id','INT NULL'],
        ['mj_orders','payment_status',"VARCHAR(40) DEFAULT 'payment_disabled'"], ['mj_orders','payment_method','VARCHAR(80) NULL'], ['mj_orders','payment_reference','VARCHAR(180) NULL'], ['mj_orders','payment_proof_path','VARCHAR(500) NULL'], ['mj_orders','payment_verified_at','DATETIME NULL'], ['mj_orders','admin_note','TEXT NULL'],
        ['mj_notifications','is_read','TINYINT(1) NOT NULL DEFAULT 0'], ['mj_notifications','read_at','DATETIME NULL'], ['mj_notifications','link_url','VARCHAR(500) NULL'],
        ['seller_leads','seller_user_id','INT NULL'], ['seller_leads','source_type','VARCHAR(40) NULL'], ['seller_leads','source_id','INT NULL'], ['seller_leads','customer_email','VARCHAR(180) NULL'], ['seller_leads','status',"VARCHAR(40) NOT NULL DEFAULT 'new'"],
        ['mj_seller_leads','seller_user_id','INT NULL'], ['mj_seller_leads','source_type','VARCHAR(40) NULL'], ['mj_seller_leads','source_id','INT NULL'], ['mj_seller_leads','customer_email','VARCHAR(180) NULL'], ['mj_seller_leads','status',"VARCHAR(40) NOT NULL DEFAULT 'new'"],
    ];
    $fixed = 0;
    foreach ($repairs as $r) {
        [$table,$column,$def] = $r;
        try {
            if (mj428_table_exists($table) && !mj428_column_exists($table,$column)) {
                $sql = 'ALTER TABLE `'.str_replace('`','',$table).'` ADD COLUMN `'.str_replace('`','',$column).'` '.$def;
                q($sql); $fixed++; mj428_repair_log('missing_column','completed',$table.'.'.$column.' added',$sql,$table.'.'.$column);
            }
        } catch (Throwable $e) { mj428_repair_log('missing_column','failed',$table.'.'.$column.' '.$e->getMessage(),$sql ?? '',$table.'.'.$column); }
    }
    return $fixed;
}}

if (!function_exists('mj428_repair_tables')) {
function mj428_repair_tables(): int {
    $sqls = [];
    $sqls['mj_seller_leads'] = "CREATE TABLE IF NOT EXISTS mj_seller_leads (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        seller_user_id BIGINT UNSIGNED NULL,
        lead_type VARCHAR(40) NULL,
        source_type VARCHAR(40) NULL,
        source_id BIGINT UNSIGNED NULL,
        item_title VARCHAR(255) NULL,
        customer_name VARCHAR(180) NULL,
        customer_email VARCHAR(180) NULL,
        customer_phone VARCHAR(80) NULL,
        customer_whatsapp VARCHAR(80) NULL,
        subject VARCHAR(255) NULL,
        message TEXT NULL,
        status VARCHAR(40) NOT NULL DEFAULT 'new',
        priority VARCHAR(40) NOT NULL DEFAULT 'normal',
        follow_up_date DATE NULL,
        last_note TEXT NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME NULL,
        INDEX idx_seller_status(seller_user_id,status), INDEX idx_source(source_type,source_id), INDEX idx_created(created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
    $sqls['seller_leads'] = str_replace('mj_seller_leads','seller_leads',$sqls['mj_seller_leads']);
    $sqls['mj_seller_lead_notes'] = "CREATE TABLE IF NOT EXISTS mj_seller_lead_notes (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, lead_id BIGINT UNSIGNED NOT NULL, user_type VARCHAR(30) NULL, user_id BIGINT UNSIGNED NULL, note TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_lead(lead_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
    $sqls['mj_seller_lead_activities'] = "CREATE TABLE IF NOT EXISTS mj_seller_lead_activities (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, lead_id BIGINT UNSIGNED NOT NULL, activity_type VARCHAR(80) NULL, activity_note TEXT NULL, created_by BIGINT UNSIGNED NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_lead(lead_id), INDEX idx_type(activity_type)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
    $sqls['seller_lead_activities'] = str_replace('mj_seller_lead_activities','seller_lead_activities',$sqls['mj_seller_lead_activities']);
    $sqls['mj_seller_lead_followups'] = "CREATE TABLE IF NOT EXISTS mj_seller_lead_followups (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, lead_id BIGINT UNSIGNED NOT NULL, follow_up_date DATETIME NULL, status VARCHAR(40) NOT NULL DEFAULT 'pending', note TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_lead_status(lead_id,status), INDEX idx_due(follow_up_date,status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
    $sqls['mj_crm_leads'] = "CREATE TABLE IF NOT EXISTS mj_crm_leads (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, seller_user_id BIGINT UNSIGNED NULL, source_type VARCHAR(40) NULL, source_id BIGINT UNSIGNED NULL, customer_name VARCHAR(180) NULL, customer_email VARCHAR(180) NULL, customer_phone VARCHAR(80) NULL, message TEXT NULL, status VARCHAR(40) NOT NULL DEFAULT 'new', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_seller_status(seller_user_id,status), INDEX idx_created(created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
    $fixed = 0;
    foreach ($sqls as $table=>$sql) {
        try { if (!mj428_table_exists($table)) { q($sql); $fixed++; mj428_repair_log('missing_table','completed',$table.' created',$sql,$table); } }
        catch (Throwable $e) { mj428_repair_log('missing_table','failed',$table.' '.$e->getMessage(),$sql,$table); }
    }
    return $fixed;
}}

if (!function_exists('mj428_repair_indexes')) {
function mj428_repair_indexes(): int {
    $idx = [
        ['mj_listings','idx_mj428_listing_speed','status,country_id,city_id,category_id,user_id,created_at'],
        ['mj_companies','idx_mj428_company_speed','status,country_id,city_id,user_id,created_at'],
        ['mj_deals','idx_mj428_deal_speed','status,country_id,city_id,category_id,seller_user_id,created_at'],
        ['mj_notifications','idx_mj428_notify_speed','user_id,is_read,created_at'],
        ['seller_leads','idx_mj428_leads_speed','seller_user_id,status,source_type,created_at'],
        ['mj_seller_leads','idx_mj428_mjleads_speed','seller_user_id,status,source_type,created_at'],
        ['mj_payments','idx_mj428_payment_speed','user_id,status,created_at'],
        ['mj_countries','idx_mj428_country_lookup','is_active,name,iso2'],
        ['mj_states','idx_mj428_state_lookup','country_id,is_active,name'],
        ['mj_cities','idx_mj428_city_lookup','country_id,state_id,is_active,name'],
    ];
    $fixed = 0;
    foreach ($idx as $r) {
        [$table,$name,$cols] = $r;
        try {
            if (!mj428_table_exists($table)) { continue; }
            $exists = one('SELECT COUNT(*) c FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND INDEX_NAME=?', [$table,$name]);
            if ((int)($exists['c'] ?? 0) === 0) {
                $cleanCols = implode(',', array_map(function($c){ return '`'.trim(str_replace('`','',$c)).'`'; }, explode(',',$cols)));
                $sql = 'ALTER TABLE `'.str_replace('`','',$table).'` ADD INDEX `'.str_replace('`','',$name).'` ('.$cleanCols.')';
                q($sql); $fixed++; mj428_repair_log('missing_index','completed',$table.'.'.$name.' added',$sql,$table.'.'.$name);
            }
        } catch (Throwable $e) { /* ignore indexes that reference missing optional columns */ }
    }
    return $fixed;
}}

if (!function_exists('mj428_run_safe_repair')) {
function mj428_run_safe_repair(string $trigger = 'manual'): array {
    mj428_ensure_schema();
    $out = ['tables'=>0,'columns'=>0,'indexes'=>0,'trigger'=>$trigger];
    $out['tables'] = mj428_repair_tables();
    $out['columns'] = mj428_repair_columns();
    $out['indexes'] = mj428_repair_indexes();
    mj428_repair_log('safe_repair','completed','Safe repair completed: '.json_encode($out), '', $trigger);
    return $out;
}}

if (!function_exists('mj428_try_repair_sql_error')) {
function mj428_try_repair_sql_error(Throwable $e, string $sql = ''): bool {
    if (!mj428_setting_bool('auto_repair_enabled', false)) { return false; }
    $msg = $e->getMessage();
    $repairable = (stripos($msg,'Base table or view not found') !== false) || (stripos($msg,'Unknown column') !== false) || (stripos($msg,'Column not found') !== false);
    if (!$repairable) { return false; }
    mj428_log_error($e, 'sql_auto_repair', $sql, 'warning');
    $result = mj428_run_safe_repair('sql_error');
    return (($result['tables'] ?? 0) + ($result['columns'] ?? 0) + ($result['indexes'] ?? 0)) > 0;
}}

if (!function_exists('mj428_friendly_error_html')) {
function mj428_friendly_error_html(Throwable $e, int $logId = 0, string $title = 'Something went wrong'): string {
    $debug = mj428_admin_can_debug();
    $safeTitle = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
    $html = '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>'.$safeTitle.'</title><style>body{font-family:Arial,sans-serif;background:#f6f8fb;margin:0;color:#0f172a}.box{max-width:760px;margin:8vh auto;background:#fff;border:1px solid #e5e7eb;border-radius:18px;padding:28px;box-shadow:0 18px 60px rgba(15,23,42,.10)}.btn{display:inline-block;background:#2563eb;color:white;padding:10px 14px;border-radius:10px;text-decoration:none;margin-right:8px}.muted{color:#64748b}.debug{background:#111827;color:#e5e7eb;border-radius:12px;padding:14px;white-space:pre-wrap;overflow:auto}code{color:#bfdbfe}</style></head><body><div class="box"><h1>'.$safeTitle.'</h1><p class="muted">Please try again. The issue has been logged for admin review.</p>';
    if ($logId) { $html .= '<p class="muted">Reference: MJ-'.$logId.'</p>'; }
    if ($debug) {
        $html .= '<h3>Admin debug details</h3><div class="debug">'.htmlspecialchars($e->getMessage().'\nFile: '.$e->getFile().'\nLine: '.$e->getLine().'\n\n'.$e->getTraceAsString(), ENT_QUOTES, 'UTF-8').'</div><p><a class="btn" href="'.(function_exists('base_url') ? base_url('admin/auto-repair.php') : '/admin/auto-repair.php').'">Open Auto Repair</a><a class="btn" href="'.(function_exists('base_url') ? base_url('admin/error-logs.php') : '/admin/error-logs.php').'">Error Logs</a></p>';
    }
    $html .= '<p><a class="btn" href="javascript:history.back()">Go Back</a><a class="btn" href="'.(function_exists('base_url') ? base_url('/') : '/').'">Home</a></p></div></body></html>';
    return $html;
}}

if (!function_exists('mj428_install_handlers')) {
function mj428_install_handlers(): void {
    static $installed = false; if ($installed) { return; } $installed = true;
    @ini_set('log_errors','1');
    @ini_set('display_errors', mj428_admin_can_debug() ? '1' : '0');
    set_exception_handler(function(Throwable $e){
        $logId = mj428_log_error($e, 'uncaught_exception', '', 'fatal');
        if (mj428_setting_bool('auto_repair_enabled', false) && mj428_try_repair_sql_error($e, '')) { /* repair logged; still show friendly */ }
        if (!headers_sent()) { http_response_code(500); }
        echo mj428_friendly_error_html($e, $logId, 'Marketplace Error');
        exit;
    });
    set_error_handler(function($severity,$message,$file,$line){
        if (!(error_reporting() & $severity)) { return false; }
        $e = new ErrorException($message, 0, $severity, $file, $line);
        mj428_log_error($e, 'php_warning', '', $severity >= E_USER_ERROR ? 'error' : 'warning');
        return false;
    });
    register_shutdown_function(function(){
        $err = error_get_last();
        if (!$err) { return; }
        if (!in_array((int)$err['type'], [E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR,E_USER_ERROR], true)) { return; }
        $e = new ErrorException((string)$err['message'], 0, (int)$err['type'], (string)$err['file'], (int)$err['line']);
        $logId = mj428_log_error($e, 'fatal_error', '', 'fatal');
        if (!headers_sent()) { http_response_code(500); echo mj428_friendly_error_html($e, $logId, 'Marketplace Fatal Error'); }
    });
}}

if (!function_exists('mj428_count_cache_get')) {
function mj428_count_cache_get(string $key, callable $callback, int $seconds = 60): int {
    try {
        mj428_ensure_schema();
        $row = one('SELECT cache_value FROM mj_count_cache WHERE cache_key=? AND (expires_at IS NULL OR expires_at>NOW()) LIMIT 1', [$key]);
        if ($row) { return (int)$row['cache_value']; }
        $value = (int)$callback();
        q('INSERT INTO mj_count_cache(cache_key,cache_group,cache_value,expires_at,created_at,updated_at) VALUES(?,?,?,?,NOW(),NOW()) ON DUPLICATE KEY UPDATE cache_value=VALUES(cache_value),expires_at=VALUES(expires_at),updated_at=NOW()', [$key,'count',$value,date('Y-m-d H:i:s', time()+$seconds)]);
        return $value;
    } catch (Throwable $e) { try { return (int)$callback(); } catch(Throwable $ignore){ return 0; } }
}}

try { mj428_ensure_ob_buffer(); mj428_install_handlers(); } catch (Throwable $ignore) {}
