<?php
/*
    *****************************************************************************
    * MEGA Digital Space - by MEGA Digital Studio                               *
    * ------------------------------------------------------------------------- *
    * CMS Website:  https://megadigital.space                                   *
    * License:  https://megadigital.space/license                               *
    * Owner:  Giorgi Basharuli                                                  *
    * Contact:  online@megadigital.studio                                       *
    * MEGA Digital Studio – Official Development Studio for MEGA Digital Space  *
    * Website:  https://megadigital.studio                                      *
    * ------------------------------------------------------------------------- *
    * Description: This file is a part of the MEGA Digital Space CMS system.    *
    * Unauthorized distribution, modification, or commercial use is strictly -  *
    * prohibited without prior written permission.                              *
    * ------------------------------------------------------------------------- *
    * Copyright (c) 2023-2025 MEGA Digital Studio.                              *
    * All rights reserved.                                                      *
    *****************************************************************************
*/

/**
 * Universal Insert Function
 * @param string $table Table name
 * @param array $data Associative array (column => value)
 * @return bool
 */
function insert($table, $data) {
    global $db_connect;

    $columns = implode(", ", array_keys($data));
    $placeholders = implode(", ", array_fill(0, count($data), "?"));
    $values = array_values($data);

    $types = determineTypes($values); // Automatically detect types
    $query = $db_connect->prepare("INSERT INTO `$table` ($columns) VALUES ($placeholders)");

  //  var_dump($types);exit();

    $query->bind_param($types, ...$values);
    $result = $query->execute();
    $query->close();

    return $result;
}

/**
 * Determine the type string for bind_param based on the value types
 * @param array $data Array of values to bind
 * @return string
 */
function determineTypes($data) {
    $types = '';
    foreach ($data as $value) {
        if (is_int($value)) {
            $types .= 'i'; // Integer
        } elseif (is_float($value)) {
            $types .= 'd'; // Double (float)
        } elseif (is_string($value)) {
            $types .= 's'; // String
        } else {
            $types .= 'b'; // Blob or other types
        }
    }
    return $types;
}


/**
 * Universal Update Function
 * @param string $table Table name
 * @param array $data Associative array (column => value) to update
 * @param array $conditions Associative array (column => value) for WHERE clause
 * @return bool
 */
function update($table, $data, $conditions) {
    global $db_connect;

    $set = implode(", ", array_map(fn($col) => "`$col` = ?", array_keys($data)));
    $where = implode(" AND ", array_map(fn($col) => "`$col` = ?", array_keys($conditions)));

    $values = array_merge(array_values($data), array_values($conditions));
    $types = determineTypes($values);

    $query = $db_connect->prepare("UPDATE `$table` SET $set WHERE $where");

    $query->bind_param($types, ...$values);
    $result = $query->execute();
    $query->close();

    return $result;
}


/**
 * Universal Select Function with JOIN support
 * @param string $table Main table name
 * @param array $columns Columns to select in format ['table.column AS alias', ...]
 * @param array $joins Array of JOINs in format ['JOIN_TYPE table ON condition', ...]
 * @param array $conditions Associative array (column => value) for WHERE clause
 * @param string $orderBy Order by clause (e.g., 'column ASC')
 * @param int $limit Number of rows to fetch
 * @param int $offset Offset for LIMIT clause
 * @return array
 */
function select(
    $table,
    $columns = ['*'],
    $joins = [],
    $conditions = [],
    $logicalOperators = [],
    $orderBy = '',
    $limit = 0,
    $offset = 0,
    $assocOnly = true
) {
    global $db_connect;

    // Формируем строку с выбранными столбцами
    $selectColumns = implode(", ", $columns);
    // Формируем строку для JOIN
    $joinClause = implode(" ", $joins);

    // Преобразуем ассоциативный массив условий в нужный формат
    if (is_assoc($conditions)) {
        $conditions = array_map(function ($column, $value) {
            return ['column' => $column, 'operator' => '=', 'value' => $value];
        }, array_keys($conditions), $conditions);
    }

    // Формируем условия WHERE
    $whereParts = [];
    $values = [];
    foreach ($conditions as $index => $condition) {
        if (is_null($condition['value'])) {
            // Для NULL не используем bind_param
            $whereParts[] = "`{$condition['column']}` IS NULL";
        } elseif (strtoupper($condition['value']) === 'NOW()') {
            // Для NOW() не используем bind_param
            $whereParts[] = "`{$condition['column']}` {$condition['operator']} NOW()";
        } else {
            // Для других значений используем bind_param
            $whereParts[] = "`{$condition['column']}` {$condition['operator']} ?";
            $values[] = $condition['value'];
        }
    }

    // Добавляем логические операторы между условиями
    $whereClause = count($whereParts) > 0
        ? "WHERE " . implode(" ", array_map(function($part, $index) use ($logicalOperators) {
            // Для первого условия логический оператор не добавляем
            return $index > 0 ? $logicalOperators[$index - 1] . " " . $part : $part;
        }, $whereParts, array_keys($whereParts)))
        : "";

    // Формируем другие части запроса (сортировка, ограничение, сдвиг)
    $orderClause = $orderBy ? "ORDER BY $orderBy" : "";
    $limitClause = $limit > 0 ? "LIMIT $limit" : "";
    $offsetClause = $offset > 0 ? "OFFSET $offset" : "";

    // Определяем типы данных для привязки параметров
    $types = determineTypes($values);

    // Строим окончательный SQL запрос
    $queryStr = "SELECT $selectColumns FROM `$table` $joinClause $whereClause $orderClause $limitClause $offsetClause";

    // Подготовка и выполнение запроса
    $query = $db_connect->prepare($queryStr);

    if ($values) {
        $query->bind_param($types, ...$values);
    }

    $query->execute();
    $result = $query->get_result();

    // Возвращаем только ассоциативный массив, если включен $assocOnly
    if ($assocOnly) {
        $rows = $result->fetch_assoc();
    } else {
        $rows = $result->fetch_all(MYSQLI_ASSOC);
    }

    // Закрытие запроса
    $query->close();

    return $rows;
}


function is_assoc($array) {
    if (!is_array($array)) return false;
    return count(array_filter(array_keys($array), 'is_string')) > 0;
}

/**
 * Universal Delete Function
 * @param string $table Table name
 * @param array $conditions Associative array (column => value) for WHERE clause
 * @return bool
 */
function delete($table, $conditions) {
    global $db_connect;

    $where = implode(" AND ", array_map(fn($col) => "`$col` = ?", array_keys($conditions)));
    $values = array_values($conditions);
    $types = determineTypes($values);

    $query = $db_connect->prepare("DELETE FROM `$table` WHERE $where");

    $query->bind_param($types, ...$values);
    $result = $query->execute();
    $query->close();

    return $result;
}
?>
