<?php
// ini_set("display_errors", 1);
/*=============================================
PDO CONNECTION TO MYSQL
=============================================*/

class Databases
{
    private static $connection = null;

    private static $dbHost = "localhost";
    private static $dbUser = "evosyspos_dev";
    private static $dbPassword = "Rachell_91";
    private static $dbName = "evosyspos_dbevosyspos";

    public static function connect()
    {
        if (self::$connection === null) { // ✅ important check
            try {
                self::$connection = new PDO(
                    "mysql:host=" . self::$dbHost . ";dbname=" . self::$dbName . ";charset=utf8mb4",
                    self::$dbUser,
                    self::$dbPassword,
                    [
                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    ]
                );
            } catch (\PDOException $e) {
                die("Error: " . $e->getMessage());
            }
        }

        return self::$connection;
    }

    public static function disconnect()
    {
        self::$connection = null;
    }
}

/*=============================================
PDO FECH ALL
=============================================*/
function executePDOFetchAll($sql, $Error = "")
{
    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        return $stmt->fetchAll();
        $message = '';
    } catch (PDOException $e) {
        $message = $Error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}


/*=============================================
PDO FECH ALL API
=============================================*/
function executePDOFetchAllAPI(string $sql, array $params = []): array
{
    try {
        $pdo = Databases::connect();
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return [
            'status'  => $rows ? 'success' : 'warning',
            'data'    => $rows,
            'count'   => count($rows),
            'message' => $rows ? 'Values found' : 'No values found'
        ];
    } catch (Throwable $e) {
        return [
            'status'  => 'error',
            'data'    => [],
            'message' => $e->getMessage()
        ];
    }
}


/*=============================================
PDO FECH ALL
=============================================*/
function executePDOFetchOneAPI(string $sql, array $params = []): array
{
    try {
        $pdo = Databases::connect();
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        $rows = $stmt->fetch(PDO::FETCH_ASSOC);

        return [
            'status'  => $rows ? 'success' : 'warning',
            'data'    => $rows,
            'count'   => $rows ? 1 : 0,
            'message' => $rows ? 'Values found' : 'No values found'
        ];
    } catch (Throwable $e) {
        return [
            'status'  => 'error',
            'data'    => [],
            'message' => $e->getMessage()
        ];
    }
}

/*=============================================
PDO FECH ONE
=============================================*/
function executePDOFetchOne($sql, $Error = "")
{
    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $Error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}

/*=============================================
PDO FECH ONE
=============================================*/
function executePDOFetchOneParams($sql, $Error = "")
{
    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $Error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}

function getProductStockById($pro_id)
{

    if (intval($pro_id) == 0) exit();

    $sql = "SELECT
        IF(pro_type = 'Service','FULL',(SELECT IFNULL(sum(pur_det_pro_qty),0) FROM tb_purchases_details WHERE pur_det_pro_id=pro_id AND pur_det_status = 'Enabled')-(SELECT IFNULL(sum(sale_det_pro_qty),0) FROM tb_sales_details WHERE sale_det_pro_id=pro_id AND sale_det_status = 'Enabled')+(SELECT IFNULL(SUM(adjust_quantity),0) FROM tb_stock_adjustments WHERE adjust_product_id = pro_id AND adjust_type = 'Increase' AND adjust_status = 'Enabled')-(SELECT IFNULL(SUM(adjust_quantity),0) FROM tb_stock_adjustments WHERE adjust_product_id = pro_id AND adjust_type = 'Decrease' AND adjust_status = 'Enabled')) AS pro_current_stock
        FROM tb_products WHERE pro_status = 'Enabled' AND pro_id = {$pro_id};";
    // exit($sql);

    return executePDOFetchOneAPI($sql);
}


/*=============================================
SELECT ALL INFORMATION FROM A ENTERPRISE
=============================================*/
function getCustomerCashBack($cus_id)
{

    $sql = "SELECT 
    SUM(CASE WHEN pay_det_cashback_status = 'Available' THEN pay_det_cashback ELSE 0 END) - 
    SUM(CASE WHEN pay_det_cashback_status = 'Used' THEN pay_det_cashback ELSE 0 END) AS available_cashback
    FROM tb_payments_details
    WHERE pay_det_cus_id = '{$cus_id}';";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
    } catch (PDOException $e) {
        return $e->getMessage();
    }
}


/*=============================================
PDO FECH ALL
=============================================*/
function getAllEnterpriseId()
{
    $sql = "SELECT ent_id FROM tb_enterprises WHERE ent_contract_status = 'Enabled' ORDER BY ent_id ASC;";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        return $stmt->fetchAll();
    } catch (PDOException $e) {
        return $e->getMessage();
    }
}


/*=============================================
SELECT ALL INFORMATION FROM A ENTERPRISE
=============================================*/
function getEnterpriseData($ent_id)
{
    if (empty($ent_id)) {
        return null;
        exit();
    }

    // $sql = "SELECT *, (select count(*) from tb_pos where pos_ent_id = ent_id) AS pos_quantity FROM tb_enterprises LEFT JOIN tb_stripe_plans ON tb_enterprises.ent_plan_id = tb_stripe_plans.plan_id WHERE ent_id = '{$ent_id}'";

    $sql = "SELECT
    e.*,
    c.customer_email,
    c.customer_name,
    p.plan_product_price_id,
    p.plan_price,
    p.plan_name,
    p.plan_interval,
    p.plan_interval_count,
    s.subs_subscription_id,
    s.subs_price_id,
    s.subs_customer_id,
    s.subs_quantity,
    s.subs_amount_unit,
    s.subs_currency,
    s.subs_interval,
    s.subs_interval_count,
    s.subscription_status,
    s.subs_created,
    s.subs_current_period_end,
    s.subs_trial_end,
    (select count(*) from tb_pos where pos_ent_id = ent_id and pos_status = 'Enabled') AS pos_quantity
    FROM tb_enterprises e
    LEFT JOIN tb_stripe_subscriptions s
        ON s.subs_subscription_id = e.ent_stripe_subscription_id
    LEFT JOIN tb_stripe_plans p
    ON p.plan_id = e.ent_plan_id
    LEFT JOIN tb_stripe_customers c
    ON c.customer_id = e.ent_stripe_customer_id
    WHERE ent_id = '{$ent_id}';";

    $error = "An error has occurred, the Enterprise information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}

/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getBranchData($pos_id)
{
    if (empty($pos_id)) {
        return null;
        exit();
    }

    $sql = "SELECT * FROM tb_pos WHERE pos_id = '{$pos_id}'";
    $error = "An error has occurred, the POS information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}

/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getCategoryData($cat_id)
{

    $sql = "SELECT * FROM tb_categories WHERE cat_id = '{$cat_id}'";
    $error = "An error has occurred, the POS information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}


/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getProductsData($pro_id)
{

    $sql = "SELECT * FROM tb_products WHERE pro_id = '{$pro_id}'";
    $error = "An error has occurred, the Product information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}


/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getUserData($user_id)
{

    $sql = "SELECT * FROM tb_users WHERE user_id = '{$user_id}'";
    $error = "An error has occurred, the User information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}

/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getPurchaseData($pur_id)
{

    $sql = "SELECT * FROM tb_purchases WHERE pur_id = '{$pur_id}'";
    $error = "An error has occurred, the User information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        $rows = $stmt->fetch(PDO::FETCH_ASSOC);
        $response = array('status' => 'warning', 'data' => $rows, 'message' => 'No values found');
        if ($rows) $response = array('status' => 'success', 'data' => $rows, 'message' => 'Values found successfully');
        return $response;
    } catch (PDOException $e) {
        $error = $e->getMessage();
        return array('status' => 'error', 'message' => $error);
    }
}


/*=============================================
PDO FECH ALL
=============================================*/
function getSaleData($sale_id)
{
    $sql = "SELECT * FROM tb_sales WHERE sale_id = '{$sale_id}'";
    $error = "An error has occurred, the User information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        $rows = $stmt->fetch(PDO::FETCH_ASSOC);
        $response = array('status' => 'warning', 'data' => $rows, 'message' => 'No values found');
        if ($rows) $response = array('status' => 'success', 'data' => $rows, 'message' => 'Values found successfully');
        return $response;
    } catch (PDOException $e) {
        $error = $e->getMessage();
        return array('status' => 'error', 'message' => $error);
    }
}

/*=============================================
PDO FECH ALL
=============================================*/
function getAllPosWithCashBack()
{
    $sql = "SELECT pos_id,pos_cash_back_availability_days,pos_cash_back_expiration_days FROM tb_pos WHERE pos_cash_back_status = 'On' ORDER BY pos_id ASC;";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        return $stmt->fetchAll();
    } catch (PDOException $e) {
        return $e->getMessage();
    }
}

/*=============================================
SELECT ALL INFORMATION FROM A POS
=============================================*/
function getCurrencySymbolByCode($currency_code)
{

    $sql = "SELECT currency_symbol FROM tb_currencies WHERE currency_code = '{$currency_code}';";
    $error = "An error has occurred, the Currency information cannot be displayed";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        return $stmt->fetch();
        $message = '';
    } catch (PDOException $e) {
        $message = $error . ' (' . $e->getMessage() . ')';
    }
    return $message;
}


/*=============================================  
FUNCTION TO RETURN LAST ID INSERTED
=============================================*/
function executeQueryPDOApi($sql, $saveOrUpdate = "", $location = "")
{
    try {
        $db = Databases::connect();
        $statement = $db->prepare($sql);
        $statement->execute();

        // Retrieve lastInsertId only for inserts, not updates
        $lastInsertId = $db->lastInsertId();

        $response = array(
            "status" => "success",
            "lastInsertId" => $lastInsertId,
            "message" => "Data saved or updated successfully",
            "type" => $saveOrUpdate
        );
    } catch (PDOException $e) {
        $response = array(
            "status" => "error",
            "message" => "{$saveOrUpdate} {$location} - {$e->getMessage()}",
            "type" => $saveOrUpdate
        );
    }

    return $response;
}


/*=============================================  
FUNCTION TO RETURN LAST ID INSERTED
=============================================*/
function executeQueryPDOApiParams(string $sqlQuery, array $paramsValue = [], string $location = "")
{
    try {
        // Connect to the database only if not already connected
        $db = Databases::connect();
        $statement = $db->prepare($sqlQuery);
        $statement->execute($paramsValue);

        // Retrieve lastInsertId only for inserts, not updates
        $lastInsertId = $db->lastInsertId();

        $response = array(
            "status" => "success",
            "lastInsertId" => $lastInsertId,
            "message" => "Data saved or updated successfully"
        );
    } catch (PDOException $e) {
        $response = array(
            "status" => "error",
            "message" => "{$location} - {$e->getMessage()}"
        );
    }

    return $response;
}

/*=============================================  
FUNCTION TO RETURN LAST ID INSERTED
=============================================*/
function executeQueryPDO($sql, $msgSuccess = "", $msgError = "")
{
    try {
        $db = Databases::connect();
        $statement = $db->prepare($sql);
        $statement->execute();
        $message = array("status" => "success", "message" => $msgSuccess);
    } catch (PDOException $e) {
        $message = array("status" => "error", "message" => "{$msgError} {$e->getMessage()}");
    }
    /* Back results as json encoded array. */
    return $message;
}

function executeQueryPDOParams($sql, $params = [], $msgSuccess = "", $msgError = "")
{
    try {
        $db = Databases::connect();
        $statement = $db->prepare($sql);
        $statement->execute($params); // ✅ bind values safely

        return [
            "status" => "success",
            "message" => $msgSuccess
        ];
    } catch (PDOException $e) {
        return [
            "status" => "error",
            "message" => "{$msgError} {$e->getMessage()}"
        ];
    }
}

function executeQueryPDOReturnLastId($sql, $saveOrUpdate = "", $location = "")
{
    try {
        $db = Databases::connect();
        $statement = $db->prepare($sql);
        $statement->execute();
        $response = array("status" => "success", "id" => $db->lastInsertId(), "message" => "Data saved successfully", "type" => $saveOrUpdate);
    } catch (PDOException $e) {
        $response = array("status" => "error", "message" => "{$saveOrUpdate} {$location} - {$e->getMessage()}", "type" => $saveOrUpdate);
    }
    return $response;
}

/*=============================================  
FUNCTION TO GET MAX ID IN TABLE
=============================================*/
// TO DELETE
function getMaxFiscalTransaction($fiscal_ent_id, $tableName, $fielToSelect, $fielWhere, $fielValue)
{
    $maxId = 0;
    $db = Databases::connect();
    $stmt = $db->prepare("SELECT IFNULL(MAX({$fielToSelect}),0) AS maxId FROM {$tableName} WHERE fiscal_ent_id = {$fiscal_ent_id} AND {$fielWhere} = '{$fielValue}'");
    $stmt->execute();
    $item = $stmt->fetch();
    $maxId = $item['maxId'];
    $maxId = intval($maxId) + 1;
    return  $maxId;
}


/*=============================================  
FUNCTION TO GET MAX ID IN TABLE
=============================================*/
function getMaxOrderNumberBySaleId($ord_det_sale_id)
{
    $maxId = 0;
    $db = Databases::connect();
    $stmt = $db->prepare("SELECT IFNULL(MAX(ord_det_number),0) AS maxId FROM tb_orders_request WHERE ord_det_sale_id = '{$ord_det_sale_id}' AND ord_det_cancel_status = 'Enabled'");
    $stmt->execute();
    $item = $stmt->fetch();
    $maxId = $item['maxId'];
    $maxId = intval($maxId) + 1;
    return  $maxId;
}


/*=============================================  
FUNCTION TO CHECK DUPLICATE
=============================================*/
function checkDuplication($tableName, $fielToSelect, $valueToChek, $extra = "")
{
    $db = Databases::connect();
    $stmt = $db->prepare("SELECT COUNT($fielToSelect) AS countId FROM $tableName WHERE $fielToSelect = '$valueToChek' $extra ;");
    $stmt->execute();
    $item = $stmt->fetch();
    $countId = $item['countId'];
    if ($countId >= 1) {
        return true;
    }
    return  false;
}


function checkDuplication_products($tableName, $fieldName1, $valueToChek1, $fieldName2, $valueToChek2)
{

    $db = Databases::connect();
    $statement = $db->prepare("SELECT COUNT($fieldName1) AS countId FROM $tableName WHERE $fieldName1 = '$valueToChek1' AND $fieldName2 = '$valueToChek2' ;");
    $statement->execute();
    $item = $statement->fetch();
    $countId = $item['countId'];
    if ($countId >= 1) {
        return true;
    }
    return  false;
}

/*=============================================  
FUNCTION TO CLEAR STRING  
=============================================*/
function funCheckInput($data)
{
    $data = strip_tags(trim($data ?? ''));
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    $data = html_entity_decode($data);
    $data = str_replace(array("\\", "¨", "º", "~", "|", "\"", "%", "&", "(", ")", "?", "¡", "¿", "[", "^", "<code>", "]", "}", "{", "¨", "´", "<", ">", '"', ";", "::", "<script>", "<script", "<script src", "<script type=", "</script>", "<?php", "?>", "INSERT INTO", "SELECT * FROM", "DELETE FROM", "DROP TABLE", "DROP DATABASES", "TRUNCATE TABLE", "SHOW TABLES", "SHOW DATABASES", "--", "=="), '', $data);
    $data = str_replace("'", "`", $data);
    $data = str_replace("'", "`", $data);
    $data = trim($data);
    return $data;
}

function mdlVerifyData($filter, $string)
{
    if (preg_match("/^" . $filter . "$/", $string)) {
        return false;
    } else {
        return true;
    }
}

function mdlGetDateTimeByZone($timeZone = 'America/New_York')
{
    if (!in_array($timeZone, \DateTimeZone::listIdentifiers(), true)) {
        $timeZone = 'UTC'; // safe fallback
    }
    $datetime = new \DateTimeImmutable('now', new \DateTimeZone($timeZone));
    return $datetime->format('Y-m-d H:i:s');
}

function mdlGetTimeByZone($timeZone = 'America/New_York')
{
    if (!in_array($timeZone, \DateTimeZone::listIdentifiers(), true)) {
        $timeZone = 'UTC'; // safe fallback
    }
    $datetime = new \DateTimeImmutable('now', new \DateTimeZone($timeZone));
    return $datetime->format('H:i:s');
}

// DYNAMIC FUNCTION TO SELECT COLUMN FROM TABLE
function fetchOneColumnsFromTable($table, $whereColumn, $valueToChek, $extra = "")
{
    $sql = "SELECT * FROM $table WHERE $whereColumn = '$valueToChek' $extra";

    try {
        $stmt = Databases::connect()->prepare($sql);
        $stmt->execute();
        /* Back results as json encoded array. */
        $rows = $stmt->fetch(PDO::FETCH_ASSOC);
        $response = array('status' => 'warning', 'data' => $rows, 'message' => 'No values found');
        if ($rows) $response = array('status' => 'success', 'data' => $rows, 'message' => 'Values found successfully');
        return $response;
    } catch (PDOException $e) {
        $error = $e->getMessage();
        return array('status' => 'error', 'message' => $error);
    }
}

// DYNAMIC FUNCTION TO SELECT COLUMN FROM TABLE
function fetchSpecificDataFromTable($tableName, $columnToSelect, $whereColumnEqualto, $columnValue, $extra = "")
{
    $sql = "SELECT $columnToSelect FROM $tableName WHERE $whereColumnEqualto = '$columnValue' $extra";
    return executePDOFetchOne($sql);
}

function generateRandomAlphanumeric($length = 8)
{
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';

    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[random_int(0, $charactersLength - 1)];
    }

    return $randomString;
}

function generateRandomDigits($length = 4)
{
    $min = pow(10, $length - 1);
    $max = pow(10, $length) - 1;
    return random_int($min, $max);
}

function createToken($table, $whereColumn, $length = "")
{

    $token = generateRandomAlphanumeric($length);
    $checkIfExist = checkDuplication($table, $whereColumn, $token);

    while ($checkIfExist == true) {
        return $token;
    }
    return $token;
}


function createTokenNumber($table, $whereColumn, $length = "")
{

    $token = generateRandomNumber($length);
    $checkIfExist = checkDuplication($table, $whereColumn, $token);

    while ($checkIfExist == true) {
        return $token;
    }
    return $token;
}

/*----------  Funcion generar codigos aleatorios  ----------*/
function generateRandomNumber(int $length): string
{
    if ($length <= 0) {
        throw new InvalidArgumentException('Length must be greater than 0');
    }

    $code = '';
    for ($i = 0; $i < $length; $i++) {
        $code .= random_int(0, 9);
    }

    return $code;
}

/*----------  Funcion generar codigos aleatorios  ----------*/
function generateRandom123Code($length, $uniqueId)
{
    $code = "";
    for ($i = 1; $i <= $length; $i++) {
        $random_number = rand(0, 9);
        $code .= $random_number;
    }
    return $uniqueId . "-" . $code;
}

/*----------  Funcion generar codigos aleatorios  ----------*/
function generateRandomABC123Code($length, $uniqueId)
{
    $code = "";
    $character = "Letter";
    for ($i = 1; $i <= $length; $i++) {
        if ($character == "Letter") {
            $random_letter = chr(rand(ord("a"), ord("z")));
            $random_letter = strtoupper($random_letter);
            $code .= $random_letter;
            $character = "Number";
        } else {
            $random_number = rand(0, 9);
            $code .= $random_number;
            $character = "Letter";
        }
    }
    return $code . "-" . $uniqueId;
}

function fnGenerateNewCancelPassword($entID)
{
    $newPassword = generateRandomNumber(4);
    $sql = "UPDATE tb_enterprises SET ent_cancel_password = :password WHERE ent_id = :id";
    executeQueryPDOParams($sql, [
        ':password' => $newPassword,
        ':id' => $entID
    ]);
}

function fnGenerateNewDiscountPassword($entID)
{
    $newPassword = generateRandomNumber(4);
    $sql = "UPDATE tb_enterprises SET ent_discount_password = :password WHERE ent_id = :id";
    executeQueryPDOParams($sql, [
        ':password' => $newPassword,
        ':id' => $entID
    ]);
}

function fnGenerateNewStatisticPassword($entID)
{
    $newPassword = generateRandomNumber(4);
    $sql = "UPDATE tb_enterprises SET ent_statistic_password = :password WHERE ent_id = :id";
    executeQueryPDOParams($sql, [
        ':password' => $newPassword,
        ':id' => $entID
    ]);
}

function getNextFiscalTransactionNumber(
    int    $fiscalEntId,
    string $tableName,
    string $fieldToSelect,
    string $fieldWhere,
    string $fieldValue
): string {
    // ⚠️ Table and column names cannot be bound as PDO parameters.
    // Ensure $tableName, $fieldToSelect, and $fieldWhere are validated
    // against a whitelist before reaching this function.
    $sql = "
        SELECT IFNULL(MAX(`{$fieldToSelect}`), 0) AS maxId
        FROM `{$tableName}`
        WHERE fiscal_ent_id = :fiscalEntId
          AND `{$fieldWhere}` = :fieldValue
    ";

    $db   = Databases::connect();
    $stmt = $db->prepare($sql);
    $stmt->execute([
        ':fiscalEntId' => $fiscalEntId,
        ':fieldValue'  => $fieldValue,
    ]);

    $maxId = (int) ($stmt->fetchColumn() ?? 0);

    return str_pad((string) ($maxId + 1), 8, '0', STR_PAD_LEFT);
}


function generateFiscalReceipt($fieldValue = "", $fiscalEntId = "", $fiscal_from = "", $fiscal_from_id = "")
{

    $tableName = 'tb_fiscal_receipt_transactions';
    $fieldToSelect = 'fiscal_number';
    $fieldWhere = 'fiscal_type';

    $nextFiscalTransactionNumber = null;

    if (!empty(trim((string) $fieldValue))) {

        $nextFiscalTransactionNumber = getNextFiscalTransactionNumber($fiscalEntId, $tableName, $fieldToSelect, $fieldWhere, $fieldValue);

        $sql_tb_fiscal = "INSERT INTO tb_fiscal_receipt_transactions (
        fiscal_ent_id
        ,fiscal_type
        ,fiscal_number
        ,fiscal_from
        ,fiscal_from_id)
        VALUES (
        '$fiscalEntId'
        ,'$fieldWhere'
        ,'$nextFiscalTransactionNumber'
        ,'$fiscal_from'
        ,'$fiscal_from_id')";

        executeQueryPDO($sql_tb_fiscal);

        return $nextFiscalTransactionNumber;
    }
}



function saveLog($log_ent_id, $log_pos_id, $log_user_id, $log_description, $currentDateTimeByZone)
{

    $user_ip = getRealIP();
    // Use ip-api.com (Free for non-commercial use)
    $api_url = "http://ip-api.com/json/" . $user_ip;
    // Fetch the data
    $response = file_get_contents($api_url);
    $data = json_decode($response, true);

    if ($data && $data['status'] == 'success') {

        $log_country_code = $data['countryCode'];
        $log_country = $data['country'];
        $log_regio_name = $data['regionName'];
        $log_timezone = $data['timezone'];
        $log_city = $data['city'];
        $log_longitude = $data['lon'];
        $log_latitude = $data['lat'];
    } else {
        $log_country_code = null;
        $log_country = null;
        $log_regio_name = null;
        $log_timezone = null;
    }

    $sql = "INSERT INTO tb_logs (
    log_ent_id
    ,log_pos_id
    ,log_user_id
    ,log_datetime
    ,log_description
    ,log_ip
    ,log_country_code
    ,log_country
    ,log_regio_name
    ,log_timezone)
    VALUES (
    '$log_ent_id'
    ,'$log_pos_id'
    ,'$log_user_id'
    ,'$currentDateTimeByZone'
    ,'$log_description'
    ,'$user_ip'
    ,'$log_country_code'
    ,'$log_country'
    ,'$log_regio_name'
    ,'$log_timezone')";

    // exit($sql);

    executeQueryPDO($sql);
}

function getShortName($fullName)
{
    // Split the full name into an array of words
    $nameParts = explode(' ', $fullName);

    // Get the first name (first element of the array)
    $firstName = $nameParts[0];

    // Get the last name (last element of the array)
    $lastName = end($nameParts);

    // Get the first letter of the last name and append a period
    $lastInitial = strtoupper($lastName[0]) . '.';

    $fullName = $firstName . ' ' . $lastInitial;
    $fullName = ucwords(strtolower($fullName));

    return $fullName;
}
