<?php
declare(strict_types=1);

require_once __DIR__ . '/db.php';

/**
 * If app_config() is defined elsewhere, remove this fallback.
 * This fallback prevents fatal errors when app_config() is missing.
 */
 
 function generate_4_digit_otp(): string {
    return str_pad((string) random_int(0, 9999), 4, '0', STR_PAD_LEFT);
}
 
 
if (!function_exists('app_config')) {
    function app_config(): array {
        // Adjust defaults to your project
        return [
            'UPLOAD_DIR'      => 'uploads',
            'MAX_UPLOAD_MB'   => 8,
            'DEMO_OTP'        => generate_4_digit_otp(),
            'COMPLETION_OTP'  => generate_4_digit_otp(),
            // If you want strict upload types:
            // 'UPLOAD_ALLOWED_EXT' => ['jpg','jpeg','png','webp','pdf'],
        ];
    }
}

/**
 * Send JSON response and terminate.
 */
function json_response($data, int $status = 200): void {
    if (!headers_sent()) {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
    }

    // Ensure we always output JSON even if non-UTF8 sneaks in
    $json = json_encode(
        $data,
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );

    if ($json === false) {
        // Fallback JSON error payload
        $json = json_encode([
            'success' => false,
            'message' => 'JSON encoding error',
            'error'   => json_last_error_msg(),
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        http_response_code(500);
    }

    echo $json;
    exit;
}

/**
 * Read JSON body safely.
 */
function read_json(): array {
    $raw = file_get_contents('php://input');
    if ($raw === false || trim($raw) === '') return [];

    $decoded = json_decode($raw, true);
    return is_array($decoded) ? $decoded : [];
}

/**
 * Basic CORS + preflight handler.
 * Call this at the top of your router script before route handling.
 *
 * Example:
 *   require_once __DIR__ . '/../../config/helpers.php';
 *   handle_cors(); // <-- add this
 */
function handle_cors(?string $allowOrigin = '*'): void {
    if (!headers_sent()) {
        header("Access-Control-Allow-Origin: " . ($allowOrigin ?? '*'));
        header("Access-Control-Allow-Credentials: true");
        header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
        header("Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS");
    }

    $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
    if (strtoupper($method) === 'OPTIONS') {
        http_response_code(204);
        exit;
    }
}

/**
 * Robust header fetcher across environments.
 */
function request_headers(): array {
    // getallheaders() may not exist in some SAPIs
    if (function_exists('getallheaders')) {
        $h = getallheaders();
        return is_array($h) ? $h : [];
    }

    $headers = [];
    foreach ($_SERVER as $k => $v) {
        if (str_starts_with($k, 'HTTP_')) {
            $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
            $headers[$name] = $v;
        }
    }
    return $headers;
}

/**
 * Extract Bearer token from Authorization header.
 */
function bearer_token(): ?string {
    $auth = $_SERVER['HTTP_AUTHORIZATION'] ?? '';

    // Some servers put it here
    if ($auth === '' && isset($_SERVER['Authorization'])) {
        $auth = (string)$_SERVER['Authorization'];
    }

    // Try all headers
    if ($auth === '') {
        $headers = request_headers();
        foreach ($headers as $k => $v) {
            if (strcasecmp($k, 'Authorization') === 0) {
                $auth = (string)$v;
                break;
            }
        }
    }

    $auth = trim($auth);
    if ($auth === '') return null;

    if (preg_match('/^Bearer\s+(.+)$/i', $auth, $m)) {
        return trim($m[1]);
    }
    return null;
}

/**
 * Auth middleware for user APIs.
 */
function require_user_auth(): array {
    $token = bearer_token();
    if (!$token) json_response(['success' => false, 'message' => 'Unauthorized'], 401);

    $pdo = db();

    $stmt = $pdo->prepare("
        SELECT ut.user_id, ut.expires_at AS token_expires_at, u.*
        FROM user_tokens ut
        JOIN users u ON u.id = ut.user_id
        WHERE ut.token = ?
          AND ut.expires_at > NOW()
        LIMIT 1
    ");
    $stmt->execute([$token]);
    $row = $stmt->fetch();

    if (!$row) json_response(['success' => false, 'message' => 'Unauthorized'], 401);

    return $row;
}

/**
 * Auth middleware for vendor APIs.
 */
function require_vendor_auth(): array {
    $token = bearer_token();
    if (!$token) json_response(['success' => false, 'message' => 'Unauthorized'], 401);

    $pdo = db();

    $stmt = $pdo->prepare("
        SELECT vt.vendor_id, vt.expires_at AS token_expires_at, v.*
        FROM vendor_tokens vt
        JOIN vendors v ON v.id = vt.vendor_id
        WHERE vt.token = ?
          AND vt.expires_at > NOW()
        LIMIT 1
    ");
    $stmt->execute([$token]);
    $row = $stmt->fetch();

    if (!$row) json_response(['success' => false, 'message' => 'Unauthorized'], 401);

    return $row;
}

/**
 * Cryptographically secure token.
 * Note: returns hex string length ~= $len (even values are best).
 */
function random_token(int $len = 64): string {
    if ($len < 16) $len = 16;
    // Convert requested length to bytes (hex expands 2x)
    $bytes = (int)ceil($len / 2);
    return bin2hex(random_bytes($bytes));
}

/**
 * Safely handle single file upload.
 * Returns relative public path (e.g. uploads/kyc/xxxx.jpg) or null.
 *
 * You can set allowed extensions by adding UPLOAD_ALLOWED_EXT in app_config().
 */

function upload_file(string $field, string $subdir = 'misc'): ?string
{
    if (!isset($_FILES[$field])) return null;

    $f = $_FILES[$field];

    if (!isset($f['error']) || $f['error'] !== UPLOAD_ERR_OK) {
        return null;
    }

    if (!is_uploaded_file($f['tmp_name'])) {
        return null;
    }

    // ✅ Absolute filesystem path to /public/uploads
    // Your current file is: /public/api/....
    // So go up one level to /public, then /uploads
    $publicDir = realpath(__DIR__ . '/../public'); // adjust if needed
    if ($publicDir === false) {
        // Fallback: try from current script directory
        $publicDir = realpath(dirname($_SERVER['SCRIPT_FILENAME']));
    }

    $uploadsRoot = $publicDir . DIRECTORY_SEPARATOR . 'uploads';
    $targetDir   = $uploadsRoot . DIRECTORY_SEPARATOR . $subdir;

    // Ensure folders exist
    if (!is_dir($targetDir)) {
        if (!mkdir($targetDir, 0775, true) && !is_dir($targetDir)) {
            return null;
        }
    }

    // Ensure writable
    if (!is_writable($targetDir)) {
        return null;
    }

    // Build safe filename
    $origName = $f['name'] ?? 'file';
    $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
    $allowed = ['jpg','jpeg','png','webp','pdf'];

    if ($ext === '' || !in_array($ext, $allowed, true)) {
        return null;
    }

    $filename = bin2hex(random_bytes(16)) . '.' . $ext;
    $destPath = $targetDir . DIRECTORY_SEPARATOR . $filename;

    // Move file
    if (!move_uploaded_file($f['tmp_name'], $destPath)) {
        return null;
    }

    // Optional: set permissions
    @chmod($destPath, 0644);

    // ✅ Return relative path you can store in DB
    // This matches your URL: /public/uploads/kyc/xxxx.jpg
    return 'uploads/' . $subdir . '/' . $filename;
}


/**
 * Keep as-is from your original file (placeholder helper).
 */
function like_today_or_tomorrow(string $slot): string {
    $slot = trim($slot);
    if ($slot === '') return '';
    return $slot;
}
