<?php
// /includes/nfc/nfc_functions.php

if (file_exists('../../../' . ($_REQUEST['tenant'] ?? '') . '/config.php')) {
    require_once('../../../' . $_REQUEST['tenant'] . '/config.php');
}
if (file_exists('/config.php')) {
    require_once('/config.php');
}

header('Content-Type: application/json; charset=utf-8');
ob_start();

ini_set('display_errors', '0');
ini_set('html_errors', '0');
error_reporting(E_ALL);

if (function_exists('mysqli_report')) {
    mysqli_report(MYSQLI_REPORT_OFF);
}

function nfc_send_json(bool $ok, string $message = '', array $extra = []): void
{
    while (ob_get_level() > 0) {
        ob_end_clean();
    }

    if (!headers_sent()) {
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    }

    echo json_encode(array_merge([
        'ok' => $ok,
        'success' => $ok,
        'message' => $message,
    ], $extra), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function nfc_request(string $key, string $default = ''): string
{
    return trim((string)($_REQUEST[$key] ?? $default));
}

function nfc_int(string $key): int
{
    return (int)($_REQUEST[$key] ?? 0);
}

function nfc_require_config(): void
{
    $tenant = $_REQUEST['tenant'] ?? '';

    if ($tenant !== '' && file_exists('../../../' . $tenant . '/config.php')) {
        require_once('../../../' . $tenant . '/config.php');
    }

    if (file_exists('/config.php')) {
        require_once('/config.php');
    }
}

function nfc_column_exists(mysqli $con, string $table, string $column): bool
{
    $table = preg_replace('/[^a-zA-Z0-9_]/', '', $table);
    $columnEscaped = $con->real_escape_string($column);

    $result = $con->query("SHOW COLUMNS FROM `$table` LIKE '$columnEscaped'");
    if (!$result) {
        return false;
    }

    $exists = $result->num_rows > 0;
    $result->free();

    return $exists;
}

function nfc_ensure_schema(mysqli $con): void
{
    // Runtime schema changes are deliberately disabled.
    // The tenant DB user may not have ALTER privileges, and this endpoint should only read/update data.
    if (!nfc_column_exists($con, 'itemdetails', 'nfc')) {
        nfc_send_json(false, 'The itemdetails.nfc column was not detected by the NFC endpoint. No ALTER was attempted.', [
            'db_error' => $con->error,
        ]);
    }
}

function nfc_extract_tag(string $value): string
{
    $value = trim($value);

    if ($value === '') {
        return '';
    }

    if (preg_match('/[?&]tag=([^&]+)/', $value, $match)) {
        return trim(rawurldecode($match[1]));
    }

    if (preg_match('/[?&]k=([^&]+)/', $value, $match)) {
        return trim(rawurldecode($match[1]));
    }

    return $value;
}

function nfc_token(): string
{
    return bin2hex(random_bytes(16));
}

function nfc_payload_url(string $tenant, string $token): string
{
    $tenant = trim($tenant);

    if (preg_match('#^https?://#i', $tenant)) {
        $base = $tenant;
    } else {
        $tenant = ltrim($tenant, "/\\");

        if ($tenant !== '') {
            $base = 'https://' . $tenant;
        } else {
            $host = trim((string)($_SERVER['HTTP_HOST'] ?? ''));
            $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';

            if ($host === '') {
                nfc_send_json(false, 'Unable to build NFC payload URL because no tenant host was supplied.');
            }

            $base = $scheme . '://' . $host;
        }
    }

    $base = preg_replace('#/+$#', '', $base);

    return $base . '/nfcreader.php?tag=' . rawurlencode($token);
}

function nfc_get_item(mysqli $con, int $itemnumber, int $clientnumber = 0): ?array
{
    if ($itemnumber <= 0) {
        return null;
    }

    if ($clientnumber > 0) {
        $stmt = $con->prepare("
            SELECT `itemnumber`, `clientnumber`, `locnumber`, `desc`, `plantnumber`, `serialnumber`, `nfc`
            FROM `itemdetails`
            WHERE `itemnumber` = ? AND `clientnumber` = ?
            LIMIT 1
        ");

        if (!$stmt) {
            nfc_send_json(false, 'DB error while preparing item lookup.', ['db_error' => $con->error]);
        }

        $stmt->bind_param('ii', $itemnumber, $clientnumber);
    } else {
        $stmt = $con->prepare("
            SELECT `itemnumber`, `clientnumber`, `locnumber`, `desc`, `plantnumber`, `serialnumber`, `nfc`
            FROM `itemdetails`
            WHERE `itemnumber` = ?
            LIMIT 1
        ");

        if (!$stmt) {
            nfc_send_json(false, 'DB error while preparing item lookup.', ['db_error' => $con->error]);
        }

        $stmt->bind_param('i', $itemnumber);
    }

    if (!$stmt->execute()) {
        $error = $stmt->error;
        $stmt->close();
        nfc_send_json(false, 'DB error while loading item.', ['db_error' => $error]);
    }

    $result = $stmt->get_result();
    $row = $result ? $result->fetch_assoc() : null;
    $stmt->close();

    return $row ?: null;
}

try {
    nfc_require_config();

    if (!isset($con) || !($con instanceof mysqli)) {
        nfc_send_json(false, 'Database connection not available.');
    }

    nfc_ensure_schema($con);

    $function = nfc_request('FUNCTION');
    $tenant = nfc_request('tenant');

    if ($function === '') {
        nfc_send_json(false, 'No FUNCTION specified.');
    }

    switch ($function) {
        case 'build_payload': {
            $itemnumber = nfc_int('itemnumber');
            $clientnumber = nfc_int('clientnumber');
            $locnumber = nfc_int('locnumber');

            $item = nfc_get_item($con, $itemnumber, $clientnumber);
            if (!$item) {
                nfc_send_json(false, 'Item not found.');
            }

            $token = nfc_token();
            $payload = nfc_payload_url($tenant, $token);

            nfc_send_json(true, 'NFC payload prepared.', [
                'token' => $token,
                'payload' => $payload,
                'itemnumber' => $itemnumber,
                'clientnumber' => $clientnumber,
                'locnumber' => $locnumber,
            ]);
        }

        case 'commit_tag': {
            $itemnumber = nfc_int('itemnumber');
            $clientnumber = nfc_int('clientnumber');
            $token = nfc_extract_tag(nfc_request('token'));
            $uid = nfc_request('uid');
            $adapter = nfc_request('adapter');

            if ($itemnumber <= 0 || $token === '') {
                nfc_send_json(false, 'Invalid NFC commit parameters.');
            }

            $item = nfc_get_item($con, $itemnumber, $clientnumber);
            if (!$item) {
                nfc_send_json(false, 'Item not found.');
            }

            $check = $con->prepare("
                SELECT `itemnumber`
                FROM `itemdetails`
                WHERE `nfc` = ? AND `itemnumber` <> ?
                LIMIT 1
            ");
            if (!$check) {
                nfc_send_json(false, 'DB error while checking NFC tag.', ['db_error' => $con->error]);
            }

            $check->bind_param('si', $token, $itemnumber);
            if (!$check->execute()) {
                $error = $check->error;
                $check->close();
                nfc_send_json(false, 'DB error while checking NFC tag.', ['db_error' => $error]);
            }

            $checkResult = $check->get_result();
            $duplicate = $checkResult ? $checkResult->fetch_assoc() : null;
            $check->close();

            if ($duplicate) {
                nfc_send_json(false, 'This NFC tag is already assigned to another item.');
            }

            $stmt = $con->prepare("
                UPDATE `itemdetails`
                SET `nfc` = ?
                WHERE `itemnumber` = ?
                LIMIT 1
            ");
            if (!$stmt) {
                nfc_send_json(false, 'DB error while preparing NFC update.', ['db_error' => $con->error]);
            }

            $stmt->bind_param('si', $token, $itemnumber);
            $saved = $stmt->execute();
            $error = $stmt->error;
            $stmt->close();

            if (!$saved) {
                nfc_send_json(false, 'DB error while saving NFC tag.', ['db_error' => $error]);
            }

            nfc_send_json(true, 'NFC tag saved.', [
                'tag' => $token,
                'uid' => $uid,
                'adapter' => $adapter,
                'payload' => nfc_payload_url($tenant, $token),
            ]);
        }

        case 'set_nfc': {
            $itemnumber = nfc_int('itemnumber');
            $clientnumber = nfc_int('clientnumber');
            $tag = nfc_extract_tag(nfc_request('tag'));

            if ($itemnumber <= 0 || $tag === '') {
                nfc_send_json(false, 'Invalid parameters.');
            }

            $item = nfc_get_item($con, $itemnumber, $clientnumber);
            if (!$item) {
                nfc_send_json(false, 'Item not found.');
            }

            $stmt = $con->prepare("UPDATE `itemdetails` SET `nfc` = ? WHERE `itemnumber` = ? LIMIT 1");
            if (!$stmt) {
                nfc_send_json(false, 'DB error while preparing NFC update.', ['db_error' => $con->error]);
            }

            $stmt->bind_param('si', $tag, $itemnumber);
            $saved = $stmt->execute();
            $error = $stmt->error;
            $stmt->close();

            nfc_send_json($saved, $saved ? 'NFC tag saved.' : 'DB error while saving NFC tag.', [
                'tag' => $tag,
                'db_error' => $saved ? '' : $error,
            ]);
        }

        case 'lookup_tag': {
            $tag = nfc_extract_tag(nfc_request('tag'));
            $payload = nfc_request('payload');

            if ($tag === '' && $payload !== '') {
                $tag = nfc_extract_tag($payload);
            }

            if ($tag === '') {
                nfc_send_json(false, 'No NFC tag value supplied.');
            }

            $stmt = $con->prepare("
                SELECT `itemnumber`, `clientnumber`, `locnumber`, `desc`, `plantnumber`, `serialnumber`, `nfc`
                FROM `itemdetails`
                WHERE `nfc` = ?
                LIMIT 1
            ");
            if (!$stmt) {
                nfc_send_json(false, 'DB error while preparing NFC lookup.', ['db_error' => $con->error]);
            }

            $stmt->bind_param('s', $tag);
            if (!$stmt->execute()) {
                $error = $stmt->error;
                $stmt->close();
                nfc_send_json(false, 'DB error while looking up NFC tag.', ['db_error' => $error]);
            }

            $result = $stmt->get_result();
            $item = $result ? $result->fetch_assoc() : null;
            $stmt->close();

            if (!$item) {
                nfc_send_json(false, 'This NFC tag is not linked to an item.', ['tag' => $tag]);
            }

            nfc_send_json(true, 'NFC tag found.', [
                'tag' => $tag,
                'item' => $item,
            ]);
        }

        case 'clear_tag':
        case 'clear_nfc': {
            $itemnumber = nfc_int('itemnumber');

            if ($itemnumber <= 0) {
                nfc_send_json(false, 'Invalid item number.');
            }

            $empty = '';
            $stmt = $con->prepare("UPDATE `itemdetails` SET `nfc` = ? WHERE `itemnumber` = ? LIMIT 1");
            if (!$stmt) {
                nfc_send_json(false, 'DB error while preparing NFC reset.', ['db_error' => $con->error]);
            }

            $stmt->bind_param('si', $empty, $itemnumber);
            $saved = $stmt->execute();
            $error = $stmt->error;
            $stmt->close();

            nfc_send_json($saved, $saved ? 'NFC tag revoked.' : 'DB error while resetting NFC tag.', [
                'db_error' => $saved ? '' : $error,
            ]);
        }

        default:
            nfc_send_json(false, 'Unknown FUNCTION.');
    }
} catch (Throwable $e) {
    error_log('EnRep NFC error: ' . $e->getMessage());
    nfc_send_json(false, 'NFC server error.', [
        'error' => $e->getMessage(),
    ]);
}
