<?php
ini_set('display_errors', '0');
error_reporting(0);

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-API-User, X-API-Pass, X-User-Id, X-Request-Id');
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, OPTIONS');
header('Access-Control-Max-Age: 86400');

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

$path = '../../../../';
require_once($path . 'config/sql.php');
require_once($path . 'deppo/tools/script/cevir.php');
require_once($path . 'config/map.php');
require_once($path . 'deppo/tools/script/fonksiyon' . $ver . '.php');

$GLOBALS['api_request_id'] = $_SERVER['HTTP_X_REQUEST_ID'] ?? ('req_' . bin2hex(random_bytes_safe(8)));
$GLOBALS['api_started_at'] = microtime(true);

function random_bytes_safe($length) {
    if (function_exists('random_bytes')) return random_bytes($length);
    if (function_exists('openssl_random_pseudo_bytes')) return openssl_random_pseudo_bytes($length);
    return substr(str_shuffle(str_repeat('0123456789abcdef', $length)), 0, $length);
}

function api_now() {
    return date('c');
}

function api_send($payload, $statusCode = 200) {
    http_response_code($statusCode);
    $payload['request_id'] = $payload['request_id'] ?? $GLOBALS['api_request_id'];
    $payload['timestamp'] = $payload['timestamp'] ?? api_now();
    echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function api_success($message, $data = [], $statusCode = 200, $legacy = []) {
    api_send(array_merge([
        'ok' => true,
        'status' => 'success',
        'message' => $message,
        'data' => $data
    ], $legacy), $statusCode);
}

function api_error($message, $statusCode = 400, $code = 'bad_request', $details = []) {
    api_send([
        'ok' => false,
        'status' => 'error',
        'code' => $code,
        'message' => $message,
        'details' => $details
    ], $statusCode);
}

function api_clean_module($module) {
    return strtolower(preg_replace('/[^a-z0-9_\-]/i', '', trim((string)$module)));
}

function api_clean_userid($userid) {
    return preg_replace('/[^a-zA-Z0-9_\-]/', '', trim((string)$userid));
}

function api_format_s19($userid) {
    return '{' . intval($userid) . '}';
}

function api_get_header_value($name) {
    $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
    return $_SERVER[$key] ?? '';
}

function api_route_module() {
    $module = $_GET['module'] ?? $_POST['module'] ?? '';
    if ($module !== '') return api_clean_module($module);

    $pathInfo = $_SERVER['PATH_INFO'] ?? '';
    if ($pathInfo === '') {
        $script = $_SERVER['SCRIPT_NAME'] ?? '';
        $uriPath = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
        if ($script && $uriPath && strpos($uriPath, $script) === 0) {
            $pathInfo = substr($uriPath, strlen($script));
        }
    }

    $segments = array_values(array_filter(explode('/', trim((string)$pathInfo, '/'))));
    return api_clean_module($segments[0] ?? '');
}

function api_input() {
    $raw = file_get_contents('php://input');
    $contentType = strtolower($_SERVER['CONTENT_TYPE'] ?? '');

    if ($raw !== '' && strpos($contentType, 'application/json') !== false) {
        $json = json_decode($raw, true);
        if (!is_array($json)) api_error('Invalid JSON payload.', 400, 'invalid_json');
        return $json;
    }

    if ($raw !== '') {
        $json = json_decode($raw, true);
        if (is_array($json)) return $json;
    }

    if (!empty($_POST)) return $_POST;
    return [];
}

function api_credentials($data) {
    $userid = api_clean_userid($data['userid'] ?? $_GET['userid'] ?? $_POST['userid'] ?? api_get_header_value('X-User-Id'));
    $user = trim((string)($data['user'] ?? $_GET['user'] ?? $_POST['user'] ?? api_get_header_value('X-API-User')));
    $pass = trim((string)($data['pass'] ?? $_GET['pass'] ?? $_POST['pass'] ?? api_get_header_value('X-API-Pass')));

    $auth = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '';
    if ($auth !== '' && stripos($auth, 'Basic ') === 0) {
        $decoded = base64_decode(substr($auth, 6), true);
        if ($decoded !== false && strpos($decoded, ':') !== false) {
            list($basicUser, $basicPass) = explode(':', $decoded, 2);
            if ($user === '') $user = $basicUser;
            if ($pass === '') $pass = $basicPass;
        }
    }

    return ['userid' => $userid, 'user' => $user, 'pass' => $pass];
}

function api_require_auth($module, $credentials) {
    $user = $credentials['user'];
    $pass = $credentials['pass'];
    $userid = $credentials['userid'];

    if ($module === 'blog' || $module === 'general') {
        $authUser = tanim('ws', 'n1', 0);
        $authPass = tanim('ws', 'n2', 0);
        if ($user !== '' && $pass !== '' && hash_equals((string)$authUser, $user) && hash_equals((string)$authPass, $pass)) {
            return;
        }
        api_error(ucfirst($module) . ' authentication failed.', 401, 'auth_failed');
    }

    if ($userid !== '' && $user !== '' && $pass !== ''
        && hash_equals(md5('user_' . $userid), $user)
        && hash_equals(md5('pass_' . $userid), $pass)) {
        return;
    }

    api_error('API authentication failed.', 401, 'auth_failed');
}

function api_log($module, $data, $credentials) {
    $logDir = __DIR__ . '/../../logs';
    if (!is_dir($logDir)) @mkdir($logDir, 0755, true);
    $safeData = $data;
    foreach (['pass', 'password', 'token', 'api_key'] as $secretKey) {
        if (isset($safeData[$secretKey])) $safeData[$secretKey] = '***';
    }
    $line = [
        'time' => date('Y-m-d H:i:s'),
        'request_id' => $GLOBALS['api_request_id'],
        'module' => $module,
        'method' => $_SERVER['REQUEST_METHOD'] ?? '',
        'userid' => $credentials['userid'] ?? '',
        'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
        'payload' => $safeData
    ];
    @file_put_contents($logDir . '/api_' . date('Ymd') . '.log', json_encode($line, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND);
}

function api_test_mode() {
    return (isset($_GET['test']) && $_GET['test'] == '1') || (isset($_POST['test']) && $_POST['test'] == '1');
}

function api_health() {
    api_success('API is healthy.', [
        'version' => '1.1',
        'service' => 'CrmPlus Cloud API',
        'modules' => ['product', 'blog', 'user'],
        'methods' => ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS']
    ]);
}

function api_docs() {
    api_success('API documentation.', [
        'base_url' => 'https://' . ($_SERVER['HTTP_HOST'] ?? 'crmplus.com.tr') . dirname($_SERVER['SCRIPT_NAME'] ?? '/'),
        'auth' => [
            'legacy' => 'userid + user=md5(user_{userid}) + pass=md5(pass_{userid})',
            'blog' => 'user/pass values from ws settings',
            'headers' => ['X-User-Id', 'X-API-User', 'X-API-Pass'],
            'basic_auth' => 'Supported as user:pass'
        ],
        'routes' => [
            'GET ?module=health' => 'Health check',
            'GET ?module=docs' => 'Docs',
            'GET ?module=general' => 'Authenticated general company settings',
            'GET ?module=blog&limit=6' => 'Authenticated blog list',
            'POST ?module=product' => ['title', 'barcode', 'price', 'price2', 'stock'],
            'POST ?module=blog' => ['title', 'desc', 'detail', 'cat', 'img'],
            'POST ?module=user' => ['name', 'email', 'phone', 'address']
        ]
    ]);
}

function api_require_payload($data) {
    if (!is_array($data) || count($data) === 0) {
        api_error('Empty request payload. Send JSON body or form data.', 400, 'empty_payload');
    }
}

function api_product($conn, $data, $userid) {
    $title = trim((string)($data['title'] ?? ''));
    $barcode = trim((string)($data['barcode'] ?? ''));
    $price = (float)($data['price'] ?? 0);
    $price2 = (float)($data['price2'] ?? 0);
    $stock = (int)($data['stock'] ?? 0);
    $s19 = api_format_s19($userid);

    if ($title === '' && $barcode === '') {
        api_error('Missing fields: title or barcode.', 422, 'missing_fields', ['required_any' => ['title', 'barcode']]);
    }

    if (api_test_mode()) {
        api_success('Product simulation.', compact('title', 'barcode', 'price', 'price2', 'stock', 's19'), 200, ['mode' => 'test']);
    }

    $stmt = $conn->prepare('SELECT id FROM t1 WHERE s19=? AND (t5=? OR t4=?) LIMIT 1');
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('sss', $s19, $barcode, $barcode);
    $stmt->execute();
    $res = $stmt->get_result();
    $existing = $res ? $res->fetch_assoc() : null;
    $stmt->close();

    if ($existing) {
        $id = (int)$existing['id'];
        $stmt = $conn->prepare('UPDATE t1 SET t1=?, pb1=?, pb2=?, s5=? WHERE id=?');
        if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
        $stmt->bind_param('sddii', $title, $price, $price2, $stock, $id);
        $stmt->execute();
        $stmt->close();
        api_success('Product updated.', ['id' => $id], 200, ['id' => $id]);
    }

    $stmt = $conn->prepare("INSERT INTO t1 (t1,t5,pb1,pb2,s5,s19,ne,ts1) VALUES (?,?,?,?,?,?, 'post', NOW())");
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('ssddis', $title, $barcode, $price, $price2, $stock, $s19);
    $stmt->execute();
    $id = (int)$stmt->insert_id;
    $stmt->close();
    api_success('Product added.', ['id' => $id], 201, ['id' => $id]);
}

function api_blog($conn, $data) {
    $title = trim((string)($data['title'] ?? ''));
    $desc = trim((string)($data['desc'] ?? ''));
    $detail = trim((string)($data['detail'] ?? ''));
    $cat = trim((string)($data['cat'] ?? ''));
    $img = trim((string)($data['img'] ?? ''));

    if ($title === '') {
        api_error('Missing fields: title.', 422, 'missing_fields', ['required' => ['title']]);
    }

    if (api_test_mode()) {
        api_success('Blog simulation.', compact('title', 'desc', 'detail', 'cat', 'img'), 200, ['mode' => 'test']);
    }

    $stmt = $conn->prepare('SELECT id FROM lang1 WHERE t1=? LIMIT 1');
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('s', $title);
    $stmt->execute();
    $res = $stmt->get_result();
    $existing = $res ? $res->fetch_assoc() : null;
    $stmt->close();

    if ($existing) {
        $blogId = (int)$existing['id'];
        $stmt = $conn->prepare("UPDATE lang1 SET t1=?, n2=?, n1=?, s2=?, ne='haber' WHERE id=?");
        if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
        $stmt->bind_param('ssssi', $title, $desc, $detail, $cat, $blogId);
        $stmt->execute();
        $stmt->close();
        api_success('Blog updated.', ['id' => $blogId], 200, ['id' => $blogId]);
    }

    $stmt = $conn->prepare("INSERT INTO lang1 (t1, n2, n1, s2, s13, ne, ts1) VALUES (?,?,?,?, 1, 'haber', NOW())");
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('ssss', $title, $desc, $detail, $cat);
    $stmt->execute();
    $blogId = (int)$stmt->insert_id;
    $stmt->close();

    if ($img !== '') {
        api_attach_blog_image($conn, $blogId, $title, $cat, $img);
    }

    api_success('Blog added.', ['id' => $blogId], 201, ['id' => $blogId]);
}

function api_public_blog_list($conn) {
    $detailId = (int)($_GET['id'] ?? 0);
    if ($detailId > 0) {
        api_blog_detail($conn, $detailId);
    }

    $limit = (int)($_GET['limit'] ?? 6);
    if ($limit < 1) $limit = 6;
    if ($limit > 24) $limit = 24;

    $baseUrl = 'https://' . ($_SERVER['HTTP_HOST'] ?? 'webatolyesi.com.tr');
    $imageBase = $baseUrl . '/deppo/tools/image/';
    $stmt = $conn->prepare("
        SELECT l.id, l.t1 AS title, l.n2 AS summary, l.n1 AS detail, l.s2 AS category, l.ts1 AS created_at,
               (
                   SELECT m.t1
                   FROM medya m
                   WHERE m.s1 = CAST(l.id AS CHAR)
                     AND (m.t3 = 'haber' OR m.ne = 'resim')
                   ORDER BY m.id DESC
                   LIMIT 1
               ) AS image
        FROM lang1 l
        WHERE l.ne = 'haber'
        ORDER BY COALESCE(l.ts1, '1970-01-01') DESC, l.id DESC
        LIMIT ?
    ");
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('i', $limit);
    $stmt->execute();
    $res = $stmt->get_result();
    $items = [];

    while ($row = $res ? $res->fetch_assoc() : null) {
        if (!$row) break;
        $title = trim((string)($row['title'] ?? ''));
        $summary = trim(strip_tags((string)($row['summary'] ?? '')));
        $detail = trim(strip_tags((string)($row['detail'] ?? '')));
        $shortDetail = function_exists('mb_substr') ? mb_substr($detail, 0, 180, 'UTF-8') : substr($detail, 0, 180);
        $image = trim((string)($row['image'] ?? ''));
        $items[] = [
            'id' => (int)$row['id'],
            'title' => $title,
            'summary' => $summary !== '' ? $summary : $shortDetail,
            'category' => trim((string)($row['category'] ?? '')),
            'image' => $image !== '' ? $imageBase . rawurlencode($image) : '',
            'url' => $baseUrl . '/?s' . (int)$row['id'],
            'created_at' => $row['created_at'] ?? ''
        ];
    }
    $stmt->close();

    api_success('Blog list.', [
        'items' => $items,
        'count' => count($items)
    ]);
}

function api_blog_detail($conn, $id) {
    $baseUrl = 'https://' . ($_SERVER['HTTP_HOST'] ?? 'webatolyesi.com.tr');
    $imageBase = $baseUrl . '/deppo/tools/image/';
    $stmt = $conn->prepare("
        SELECT l.id, l.t1 AS title, l.n2 AS summary, l.n1 AS detail, l.s2 AS category, l.ts1 AS created_at,
               (
                   SELECT m.t1
                   FROM medya m
                   WHERE m.s1 = CAST(l.id AS CHAR)
                     AND (m.t3 = 'haber' OR m.ne = 'resim')
                   ORDER BY m.id DESC
                   LIMIT 1
               ) AS image
        FROM lang1 l
        WHERE l.ne = 'haber' AND l.id = ?
        LIMIT 1
    ");
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $res = $stmt->get_result();
    $row = $res ? $res->fetch_assoc() : null;
    $stmt->close();

    if (!$row) {
        api_error('Blog post not found.', 404, 'not_found');
    }

    $image = trim((string)($row['image'] ?? ''));
    api_success('Blog detail.', [
        'item' => [
            'id' => (int)$row['id'],
            'title' => trim((string)($row['title'] ?? '')),
            'summary' => trim(strip_tags((string)($row['summary'] ?? ''))),
            'detail' => (string)($row['detail'] ?? ''),
            'category' => trim((string)($row['category'] ?? '')),
            'image' => $image !== '' ? $imageBase . rawurlencode($image) : '',
            'url' => $baseUrl . '/?s' . (int)$row['id'],
            'created_at' => $row['created_at'] ?? ''
        ]
    ]);
}

function api_public_url($url) {
    $url = trim((string)$url);
    if ($url === '') return '';
    if (strpos($url, '//') === 0) return 'https:' . $url;
    if (preg_match('~^https?://~i', $url)) return $url;

    $host = $_SERVER['HTTP_HOST'] ?? 'webatolyesi.com.tr';
    if ($url[0] === '/') return 'https://' . $host . $url;
    return 'https://' . $host . '/' . ltrim($url, '/');
}

function api_general() {
    global $firma, $fdesc, $ftel, $ftel2, $ftel3, $fgsm, $fgsm2, $fwhatsapp, $fmail, $fmail2;
    global $fadres, $fadres2, $weburl, $logo, $logo2, $favicon, $title, $description, $keywords;
    global $lfacebook, $ltwitter, $linstagram, $llinkedin, $lyoutube, $lgplus, $skype, $module, $clanguage, $currency;

    $phones = array_values(array_filter([$ftel ?? '', $ftel2 ?? '', $ftel3 ?? '', $fgsm ?? '', $fgsm2 ?? '']));
    $emails = array_values(array_filter([$fmail ?? '', $fmail2 ?? '']));
    $addresses = array_values(array_filter([$fadres ?? '', $fadres2 ?? '']));
    $whatsapp = preg_replace('/[^0-9+]/', '', (string)($fwhatsapp ?? ''));
    $siteUrl = api_public_url($weburl ?? ('https://' . ($_SERVER['HTTP_HOST'] ?? 'webatolyesi.com.tr')));

    api_success('General settings.', [
        'company' => [
            'name' => (string)($firma ?? ''),
            'description' => (string)($fdesc ?? ''),
            'website' => $siteUrl
        ],
        'contact' => [
            'phone' => $phones[0] ?? '',
            'phones' => $phones,
            'mobile' => (string)($fgsm ?? ''),
            'whatsapp' => $whatsapp,
            'whatsapp_url' => $whatsapp !== '' ? 'https://wa.me/' . ltrim($whatsapp, '+') : '',
            'email' => $emails[0] ?? '',
            'emails' => $emails,
            'address' => $addresses[0] ?? '',
            'addresses' => $addresses
        ],
        'media' => [
            'logo' => api_public_url($logo ?? ''),
            'logo_secondary' => api_public_url($logo2 ?? ''),
            'favicon' => api_public_url($favicon ?? '')
        ],
        'social' => [
            'facebook' => (string)($lfacebook ?? ''),
            'twitter' => (string)($ltwitter ?? ''),
            'instagram' => (string)($linstagram ?? ''),
            'linkedin' => (string)($llinkedin ?? ''),
            'youtube' => (string)($lyoutube ?? ''),
            'google' => (string)($lgplus ?? ''),
            'skype' => (string)($skype ?? '')
        ],
        'seo' => [
            'title' => (string)($title ?? ''),
            'description' => (string)($description ?? ''),
            'keywords' => (string)($keywords ?? '')
        ],
        'settings' => [
            'language' => (string)($clanguage ?? 'tr'),
            'currency' => (string)($module['currency'] ?? $currency ?? 'TRY'),
            'timezone' => (string)($module['wtimezone'] ?? date_default_timezone_get())
        ]
    ]);
}

function api_attach_blog_image($conn, $blogId, $title, $cat, $img) {
    $imgDir = __DIR__ . '/../../../image/';
    if (!is_dir($imgDir)) @mkdir($imgDir, 0755, true);

    $ext = strtolower(pathinfo(parse_url($img, PHP_URL_PATH) ?: $img, PATHINFO_EXTENSION));
    if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp', 'gif'], true)) $ext = 'jpg';
    $filename = 'blog_' . $blogId . '_' . time() . '.' . $ext;
    $filePath = $imgDir . $filename;

    $saved = false;
    if (filter_var($img, FILTER_VALIDATE_URL)) {
        $context = stream_context_create(['http' => ['timeout' => 8], 'https' => ['timeout' => 8]]);
        $imgContent = @file_get_contents($img, false, $context);
        if ($imgContent !== false) $saved = (bool)@file_put_contents($filePath, $imgContent);
    } elseif (strpos($img, 'base64,') !== false) {
        $parts = explode('base64,', $img, 2);
        $decoded = base64_decode($parts[1], true);
        if ($decoded !== false) $saved = (bool)@file_put_contents($filePath, $decoded);
    } elseif (is_file($img)) {
        $saved = @copy($img, $filePath);
    }

    if (!$saved) return;

    @copy($filePath, $imgDir . 'k_' . $filename);
    $ne = 'resim';
    $s1 = (string)$blogId;
    $s2 = '1';
    $s3 = '0';
    $s4 = '0';
    $t3 = 'haber';
    $lang = $_SESSION['lang'] ?? 'lang1';
    $stmt = $conn->prepare('INSERT INTO medya (ne,s1,s2,s3,s4,t1,t3,t6,t2) VALUES (?,?,?,?,?,?,?,?,?)');
    if ($stmt) {
        $stmt->bind_param('sssssssss', $ne, $s1, $s2, $s3, $s4, $filename, $t3, $lang, $title);
        $stmt->execute();
        $stmt->close();
    }
}

function api_user($conn, $data, $userid) {
    $name = trim((string)($data['name'] ?? ''));
    $email = trim((string)($data['email'] ?? ''));
    $phone = trim((string)($data['phone'] ?? ''));
    $address = trim((string)($data['address'] ?? ''));
    $s19 = api_format_s19($userid);
    $emailB64 = base64_encode($email);

    if ($name === '' && $email === '') {
        api_error('Missing fields: name or email.', 422, 'missing_fields', ['required_any' => ['name', 'email']]);
    }

    if (api_test_mode()) {
        api_success('User simulation.', compact('name', 'email', 'phone', 'address', 's19'), 200, ['mode' => 'test']);
    }

    $stmt = $conn->prepare('SELECT id FROM t5 WHERE s19=? AND (t2=? OR t4=?) LIMIT 1');
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('sss', $s19, $emailB64, $phone);
    $stmt->execute();
    $res = $stmt->get_result();
    $existing = $res ? $res->fetch_assoc() : null;
    $stmt->close();

    if ($existing) {
        $id = (int)$existing['id'];
        $stmt = $conn->prepare('UPDATE t5 SET t1=?, t2=?, t4=?, n6=? WHERE id=?');
        if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
        $stmt->bind_param('ssssi', $name, $emailB64, $phone, $address, $id);
        $stmt->execute();
        $stmt->close();
        api_success('User updated.', ['id' => $id], 200, ['id' => $id]);
    }

    $stmt = $conn->prepare('INSERT INTO t5 (t1,t2,t4,n6,s19,created_at) VALUES (?,?,?,?,?,NOW())');
    if (!$stmt) api_error('Database prepare failed.', 500, 'db_prepare');
    $stmt->bind_param('sssss', $name, $emailB64, $phone, $address, $s19);
    $stmt->execute();
    $id = (int)$stmt->insert_id;
    $stmt->close();
    api_success('User added.', ['id' => $id], 201, ['id' => $id]);
}

try {
    $module = api_route_module();
    if ($module === '' || $module === 'health') api_health();
    if ($module === 'docs' || $module === 'openapi') api_docs();

    if (!in_array($module, ['product', 'blog', 'user', 'general'], true)) {
        api_error('Invalid module.', 404, 'invalid_module', ['allowed' => ['product', 'blog', 'user', 'general']]);
    }

    $data = api_input();
    $credentials = api_credentials($data);
    api_require_auth($module, $credentials);

    if ($module === 'general' && ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET') {
        api_general();
    }

    if ($module === 'blog' && ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET') {
        api_public_blog_list($conn);
    }

    api_require_payload($data);
    api_log($module, $data, $credentials);

    if ($module === 'product') api_product($conn, $data, $credentials['userid']);
    if ($module === 'blog') api_blog($conn, $data);
    if ($module === 'user') api_user($conn, $data, $credentials['userid']);

    api_error('Invalid module.', 404, 'invalid_module');
} catch (Throwable $e) {
    api_error('Internal server error.', 500, 'internal_error');
} catch (Exception $e) {
    api_error('Internal server error.', 500, 'internal_error');
}
?>
