<?php
// --- HTTP HEADERS FOR CORS ---
header("Content-Type: application/json");

// Allowed origins for the chat API. Lock down to your real domain(s).
// localhost allowed with any port via prefix match (dev servers pick arbitrary ports).
$allowed_origins = [
    "https://balajij.dev",
    "https://www.balajij.dev",
];
$request_origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
$is_local_dev = (
    $request_origin === 'http://localhost' ||
    $request_origin === 'http://127.0.0.1' ||
    preg_match('#^https?://(localhost|127\.0\.0\.1)(:\d+)?$#', $request_origin) === 1
);
$origin_allowed = in_array($request_origin, $allowed_origins, true) || $is_local_dev;

if ($origin_allowed) {
    header("Access-Control-Allow-Origin: $request_origin");
    header("Vary: Origin");
} else {
    header("Access-Control-Allow-Origin: https://balajij.dev");
    header("Vary: Origin");
}
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Methods: POST, OPTIONS");

// Handle CORS Preflight OPTIONS Request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

// Only allow POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(["error" => "Only POST requests are allowed"]);
    exit(0);
}

// --- REQUEST SIZE LIMIT (8 KB should be plenty for a chat message) ---
if (isset($_SERVER['CONTENT_LENGTH']) && (int)$_SERVER['CONTENT_LENGTH'] > 8192) {
    http_response_code(413);
    echo json_encode(["error" => "Request body too large"]);
    exit(0);
}

// --- RATE LIMIT (per IP, 15 requests / 60 seconds) ---
// Supports Redis (set REDIS_URL) or file-based fallback.
// Disable via RATE_LIMIT_DISABLED=1 for serverless/load-balanced setups.
function rate_limit_check($ip, $max_requests = 15, $window_seconds = 60) {
    if (getenv('RATE_LIMIT_DISABLED') === '1') return false;

    $redis_url = getenv('REDIS_URL');
    if ($redis_url && extension_loaded('redis')) {
        try {
            $redis = new Redis();
            $redis->connect(parse_url($redis_url, PHP_URL_HOST), parse_url($redis_url, PHP_URL_PORT) ?? 6379);
            if ($auth = parse_url($redis_url, PHP_URL_PASS)) $redis->auth($auth);
            $key = "rl:$ip";
            $count = $redis->incr($key);
            if ($count === 1) $redis->expire($key, $window_seconds);
            return $count > $max_requests;
        } catch (Exception $e) {
            // fall through to file-based
        }
    }

    // File-based fallback (single-server only)
    $cache_dir = sys_get_temp_dir() . '/chat_rl';
    if (!is_dir($cache_dir)) { @mkdir($cache_dir, 0700, true); }
    $bucket_file = $cache_dir . '/' . md5($ip) . '.json';
    $now = time();
    $bucket = ['start' => $now, 'count' => 0];
    if (file_exists($bucket_file)) {
        $raw = @file_get_contents($bucket_file);
        $decoded = $raw ? json_decode($raw, true) : null;
        if (is_array($decoded) && isset($decoded['start'], $decoded['count'])) {
            if (($now - (int)$decoded['start']) < $window_seconds) {
                $bucket = $decoded;
            }
        }
    }
    $bucket['count']++;
    @file_put_contents($bucket_file, json_encode($bucket), LOCK_EX);
    return $bucket['count'] > $max_requests;
}

$client_ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
if (rate_limit_check($client_ip)) {
    http_response_code(429);
    echo json_encode(["error" => "Too many requests. Please slow down."]);
    exit(0);
}

// --- SECURE ENV VARIABLE LOOKUP ---
// Prefers $_ENV (populated by php-fpm / .env loaders), falls back to getenv().
function get_env_var($key_to_find) {
    if (isset($_ENV[$key_to_find])) return $_ENV[$key_to_find];
    $val = getenv($key_to_find);
    return $val !== false ? $val : null;
}

// --- PARSE REQUEST BODY ---
$input_raw = file_get_contents("php://input");
$input_data = json_decode($input_raw, true);
$user_message = isset($input_data['message']) ? trim($input_data['message']) : '';
$mode = isset($input_data['mode']) ? trim($input_data['mode']) : 'about';
$context = isset($input_data['context']) ? trim($input_data['context']) : '';

// Cap message + context length to keep prompt size bounded.
$user_message = mb_substr($user_message, 0, 1000);
$context      = mb_substr($context, 0, 8000);
$mode         = ($mode === 'general') ? 'general' : 'about';

if (empty($user_message)) {
    http_response_code(400);
    echo json_encode(["error" => "Message content cannot be empty"]);
    exit(0);
}

// --- SYSTEM PROMPT GENERATION ---
$system_prompt_about = "You are a helpful AI assistant for this website. Your purpose is to answer questions based ONLY on the provided website content.\n\n"
    . "CRITICAL WRITING STYLE RULES:\n"
    . "- Keep your responses extremely short, direct, and concise (under 2-3 sentences where possible).\n"
    . "- Use clean bullet points where appropriate to present lists or multiple details.\n"
    . "- Do not include filler words, extra greetings, or conversational fluff.\n\n"
    . "WEBSITE CONTENT (Context):\n"
    . $context . "\n\n"
    . "GUARDRAILS:\n"
    . "- Strictly keep answers focused on the information provided in the WEBSITE CONTENT above.\n"
    . "- If the information is not present in the content, politely state: \"I don't have that information based on the website content.\"\n"
    . "- Do not make up any facts.\n";

$system_prompt_general = "You are a helpful, smart, and friendly general AI assistant.\n\n"
    . "CRITICAL WRITING STYLE:\n"
    . "- ALWAYS keep your responses extremely short, direct, and concise (under 2-3 sentences where possible).\n"
    . "- ALWAYS organize information using clear, clean bullet points instead of long paragraphs or walls of text.\n"
    . "- Avoid filler words or conversational fluff.\n"
    . "- You are allowed to answer any query, solve problems, write code, tell jokes, or provide factual information on any topic.";

$system_prompt = ($mode === 'general') ? $system_prompt_general : $system_prompt_about;

// --- FETCH API KEY AND MODEL ---
$api_key = get_env_var("NVIDIA_API_KEY");
$env_model = get_env_var("NVIDIA_MODEL");

if (!$api_key) {
    echo json_encode([
        "response" => "Hello! The NVIDIA API key is not configured in the backend `.env` file yet, so I cannot query the AI model directly."
    ]);
    exit(0);
}

// --- QUERY NVIDIA API ---
$invoke_url = "https://integrate.api.nvidia.com/v1/chat/completions";
$model_name = $env_model ? $env_model : "qwen/qwen3.5-397b-a17b"; // Fallback to Qwen if not specified in .env

$payload = [
    "model" => $model_name,
    "messages" => [
        ["role" => "system", "content" => $system_prompt],
        ["role" => "user", "content" => $user_message]
    ],
    "temperature" => 0.2,
    "top_p" => 0.7,
    "max_tokens" => 512,
];

$ch = curl_init($invoke_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer " . $api_key,
    "Accept: application/json",
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo json_encode(["error" => "Curl Error: " . curl_error($ch)]);
    curl_close($ch);
    exit(0);
}
curl_close($ch);

if ($http_code !== 200) {
    echo json_encode(["error" => "NVIDIA API Error (HTTP $http_code): $response"]);
    exit(0);
}

$decoded_response = json_decode($response, true);
$bot_reply = "Sorry, I couldn't process the response.";

if (isset($decoded_response['choices'][0]['message']['content'])) {
    $bot_reply = $decoded_response['choices'][0]['message']['content'];
}

// --- XSS HARDENING: strip dangerous HTML/script vectors from the LLM reply ---
// Frontend uses textContent, but defense-in-depth: neutralize HTML entities & dangerous patterns.
$bot_reply = htmlspecialchars($bot_reply, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$bot_reply = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $bot_reply);
$bot_reply = preg_replace('#on\w+\s*=\s*["\'][^"\']*["\']#i', '', $bot_reply);
$bot_reply = preg_replace('#javascript\s*:#i', '', $bot_reply);
$bot_reply = preg_replace('#<(img|svg|iframe|object|embed|form|input|textarea|select|video|audio)[^>]*>#i', '', $bot_reply);
$bot_reply = mb_substr($bot_reply, 0, 4000);

echo json_encode(["response" => $bot_reply]);
?>
