<?php
/**
 * Shared helper functions used across all API endpoints.
 */

function send_json(array $data, int $statusCode = 200): void
{
    http_response_code($statusCode);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

function send_success($data = null, string $message = '', int $statusCode = 200): void
{
    $payload = ['success' => true];
    if ($message !== '') {
        $payload['message'] = $message;
    }
    if ($data !== null) {
        $payload['data'] = $data;
    }
    send_json($payload, $statusCode);
}

function send_error(string $message, int $statusCode = 400, array $extra = []): void
{
    send_json(array_merge(['success' => false, 'message' => $message], $extra), $statusCode);
}

function get_json_input(): array
{
    $raw = file_get_contents('php://input');
    if (!$raw) {
        return [];
    }
    $decoded = json_decode($raw, true);
    return is_array($decoded) ? $decoded : [];
}

function require_fields(array $input, array $fields): void
{
    $missing = [];
    foreach ($fields as $field) {
        if (!isset($input[$field]) || (is_string($input[$field]) && trim($input[$field]) === '')) {
            $missing[] = $field;
        }
    }
    if (!empty($missing)) {
        send_error('Missing required field(s): ' . implode(', ', $missing), 422);
    }
}

function clean_str($value): string
{
    if ($value === null) {
        return '';
    }
    return trim(strip_tags((string) $value));
}

function is_valid_email(string $email): bool
{
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

/**
 * mb_strimwidth() has inconsistent behavior on some shared-hosting mbstring
 * builds. Custom UTF-8 safe truncate helper used instead across the app.
 */
function safe_truncate(string $text, int $maxLength, string $suffix = '...'): string
{
    if (mb_strlen($text, 'UTF-8') <= $maxLength) {
        return $text;
    }
    return mb_substr($text, 0, $maxLength, 'UTF-8') . $suffix;
}

function generate_otp(int $digits = 6): string
{
    $min = (int) str_pad('1', $digits, '0');
    $max = (int) str_pad('', $digits, '9');
    return (string) random_int($min, $max);
}

function generate_token(int $bytes = 32): string
{
    return bin2hex(random_bytes($bytes));
}

function get_client_ip(): string
{
    foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'] as $key) {
        if (!empty($_SERVER[$key])) {
            $parts = explode(',', $_SERVER[$key]);
            return trim($parts[0]);
        }
    }
    return '0.0.0.0';
}

function get_bearer_token(): ?string
{
    $header = $_SERVER['HTTP_AUTHORIZATION'] ?? ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '');
    if (!$header && function_exists('apache_request_headers')) {
        $headers = apache_request_headers();
        $header = $headers['Authorization'] ?? '';
    }
    if (preg_match('/Bearer\s+(\S+)/i', $header, $matches)) {
        return $matches[1];
    }
    return null;
}

function paginate_params(): array
{
    $page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
    $perPage = isset($_GET['per_page']) ? min(100, max(5, (int) $_GET['per_page'])) : 20;
    $offset = ($page - 1) * $perPage;
    return [$page, $perPage, $offset];
}

function apply_cors(): void
{
    header('Access-Control-Allow-Origin: ' . CORS_ALLOWED_ORIGIN);
    header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, Authorization, Accept');
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        http_response_code(204);
        exit;
    }
}
