<?php
// api/config.php
declare(strict_types=1);

// 🔐 Schimbă asta cu un secret lung (32+)
const API_KEY = 'SCHIMBA_CU_UN_SECRET_LUNG_AICI';

// ✅ Baza workerului
const WORKER_BASE = '/home4/etimpuls/audit_worker/app';
const QUEUE_DIR   = WORKER_BASE . '/queue';
const OUTPUTS_DIR = WORKER_BASE . '/outputs';

// DEMO rules
const DEMO_MAX_PAGES = 50;

// ✅ cooldown DEMO per device (6 ore recomandat)
const DEMO_LIMIT_SECONDS = 6 * 60 * 60;

// ✅ (optional) cooldown per IP (anti-abuz prin curl fără cookies)
// recomand 10-30 minute, ca să nu deranjeze userii legitimi
const DEMO_IP_LIMIT_SECONDS = 20 * 60;

// Schimba cu ceva al tau (orice text lung), ca sa nu poata ghici fingerprint-ul
const FP_SALT = 'SCHIMBA_AICI_CU_UN_SALT_LUNG_UNIC_2025';

// Folder rate limit (fisiere lock)
const RATE_LIMIT_DIR = OUTPUTS_DIR . '/ratelimit';

// Dacă ai WP pe alt subdomeniu și vrei CORS, pune domeniul tău aici.
// Ex: https://etimpulseo.ro
const ALLOW_ORIGIN = '*'; // sau 'https://etimpulseo.ro'

function cors_headers(): void {
    header('Access-Control-Allow-Origin: ' . ALLOW_ORIGIN);
    header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, X-API-Key');
}

function respond(array $data, int $code = 200): void {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function require_auth(): void {
    $key = $_SERVER['HTTP_X_API_KEY'] ?? ($_GET['key'] ?? '');
    if (!$key || !hash_equals(API_KEY, (string)$key)) {
        respond(['ok' => false, 'error' => 'Unauthorized'], 401);
    }
}

/**
 * ✅ IP real, compatibil Cloudflare / proxy
 */
function get_client_ip(): string {
    $candidates = [
        $_SERVER['HTTP_CF_CONNECTING_IP'] ?? null,
        $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null,
        $_SERVER['HTTP_X_REAL_IP'] ?? null,
        $_SERVER['REMOTE_ADDR'] ?? null,
    ];
    foreach ($candidates as $ip) {
        if (!$ip) continue;
        $ip = trim(explode(',', (string)$ip)[0]);
        if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip;
    }
    return '0.0.0.0';
}

function ensure_dirs(): void {
    $dirs = [
        QUEUE_DIR,
        QUEUE_DIR . '/pending',
        QUEUE_DIR . '/running',
        QUEUE_DIR . '/done',
        QUEUE_DIR . '/failed',
        OUTPUTS_DIR,
        OUTPUTS_DIR . '/xlsx',
        RATE_LIMIT_DIR,
    ];
    foreach ($dirs as $d) {
        if (!is_dir($d)) @mkdir($d, 0755, true);
    }
}

function normalize_url(string $url): string {
    $url = trim($url);
    if ($url === '') return '';
    if (!preg_match('~^https?://~i', $url)) $url = 'https://' . $url;
    return $url;
}

function is_valid_url(string $url): bool {
    if (!filter_var($url, FILTER_VALIDATE_URL)) return false;
    $parts = parse_url($url);
    if (!$parts || empty($parts['host'])) return false;
    $scheme = strtolower($parts['scheme'] ?? '');
    return in_array($scheme, ['http', 'https'], true);
}

function make_job_id(): string {
    return bin2hex(random_bytes(12)); // 24 hex
}

/**
 * ✅ Cookie FP (device fingerprint id)
 *  - îl setăm dacă lipsește
 *  - SameSite=Lax, Secure pe HTTPS
 */
function ensure_demo_fingerprint_cookie(): string {
    $name = 'etseo_fp';
    if (!empty($_COOKIE[$name])) return (string)$_COOKIE[$name];

    $val = bin2hex(random_bytes(16));
    $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');

    // 30 zile
    setcookie($name, $val, [
        'expires'  => time() + 30*24*60*60,
        'path'     => '/',
        'secure'   => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);

    $_COOKIE[$name] = $val;
    return $val;
}

function demo_fp_hash(string $fp): string {
    $ua = (string)($_SERVER['HTTP_USER_AGENT'] ?? '');
    $al = (string)($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '');
    return hash('sha256', $fp . '|' . $ua . '|' . $al . '|' . FP_SALT);
}

/**
 * ✅ Rate limit pe DEVICE (cookie fp)
 */
function rate_limit_demo_by_fp_or_die(string $fp): void {
    $hash = demo_fp_hash($fp);
    $lock = RATE_LIMIT_DIR . '/demo_fp_' . $hash . '.json';

    if (is_file($lock)) {
        $data = json_decode((string)@file_get_contents($lock), true);
        $last = (int)($data['ts'] ?? 0);
        if ($last > 0 && (time() - $last) < DEMO_LIMIT_SECONDS) {
            $remain = DEMO_LIMIT_SECONDS - (time() - $last);
            respond([
                'ok' => false,
                'error' => 'LIMIT_DEMO_DEVICE',
                'message' => 'Ai rulat deja DEMO pe acest device. Revino după ce expiră perioada.',
                'retry_after_sec' => $remain,
            ], 429);
        }
    }
}

/**
 * ✅ Lock pe FP (scriem după ce jobul a fost creat)
 */
function write_demo_lock_fp(string $fp, string $job_id): void {
    $hash = demo_fp_hash($fp);
    $lock = RATE_LIMIT_DIR . '/demo_fp_' . $hash . '.json';
    @file_put_contents($lock, json_encode([
        'ts' => time(),
        'job_id' => $job_id,
        'ip' => get_client_ip(),
    ], JSON_UNESCAPED_SLASHES));
}

/**
 * ✅ (Optional) Rate limit pe IP REAL (plasă anti-abuz, ex curl fără cookies)
 * IMPORTANT: folosește get_client_ip() (CF-aware), NU REMOTE_ADDR direct.
 */
function rate_limit_demo_by_ip_or_die(int $cooldown_seconds = DEMO_IP_LIMIT_SECONDS): void {
    if ($cooldown_seconds <= 0) return;

    $ip = get_client_ip();
    $safe = preg_replace('~[^a-z0-9\.\-:]~i', '_', $ip);
    $lock = RATE_LIMIT_DIR . '/demo_ip_' . $safe . '.txt';

    $now = time();
    if (is_file($lock)) {
        $last = (int)trim((string)@file_get_contents($lock));
        if ($last > 0 && ($now - $last) < $cooldown_seconds) {
            $remain = $cooldown_seconds - ($now - $last);
            respond([
                'ok' => false,
                'error' => 'LIMIT_DEMO_IP',
                'message' => 'Ai rulat DEMO recent de pe această conexiune. Revino puțin mai târziu.',
                'retry_after_sec' => $remain,
            ], 429);
        }
    }
    @file_put_contents($lock, (string)$now, LOCK_EX);
}

function queue_write_pending(string $job_id, array $job): string {
    $path = QUEUE_DIR . '/pending/' . $job_id . '.json';
    $json = json_encode($job, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if ($json === false) throw new RuntimeException('JSON encode failed');
    if (@file_put_contents($path, $json) === false) throw new RuntimeException('Cannot write job file to pending');
    @chmod($path, 0664);
    return $path;
}

function find_job_state(string $job_id): array {
    $paths = [
        'pending' => QUEUE_DIR . '/pending/' . $job_id . '.json',
        'running' => QUEUE_DIR . '/running/' . $job_id . '.json',
        'done'    => QUEUE_DIR . '/done/' . $job_id . '.json',
        'failed'  => QUEUE_DIR . '/failed/' . $job_id . '.json',
    ];
    foreach ($paths as $state => $p) {
        if (file_exists($p)) return ['state' => $state, 'path' => $p];
    }
    return ['state' => 'missing', 'path' => ''];
}
