<?php
function encrypt_value($plaintext, $key) {
	if ($plaintext === null) return null;
	$iv = random_bytes(16);
	$ciphertext = openssl_encrypt($plaintext, 'AES-256-CBC', hex2bin($key), OPENSSL_RAW_DATA, $iv);
	return base64_encode($iv.$ciphertext);
}

function decrypt_value($encrypted, $key) {
	if ($encrypted === null) return null;
	$data = base64_decode($encrypted);
	if ($data === false || strlen($data) < 17) return null;
	$iv = substr($data, 0, 16);
	$ciphertext = substr($data, 16);
	return openssl_decrypt($ciphertext, 'AES-256-CBC', hex2bin($key), OPENSSL_RAW_DATA, $iv);
}

function hash_value($value, $pepper) {
	if ($value === null) return null;
	return hash('sha256', $pepper.$value);
}

function save_ini_file($file, $assoc_array) {
	$content = '';
	foreach ($assoc_array as $section => $values) {
		$content .= "[$section]\n";
		foreach ($values as $key => $value) {
			$content .= "$key = \"$value\"\n";
		}
		$content .= "\n";
	}
	file_put_contents($file, $content);
}

function update_indexes($table, $field, $mode) {
	global $conn;

	$indexes = [];
	$result = $conn->prepare("SHOW INDEXES FROM ".$table);
	$result->execute();

	while ($arr = $result->fetch()) {
		$index_name = $arr['Key_name'];
		$col_name = $arr['Column_name'];
		$non_unique = $arr['Non_unique'];
		$index_type = $arr['Index_type'];

		if (!isset($indexes[$index_name])) {
			$indexes[$index_name] = [
				'unique' => ($non_unique == 0),
				'type' => $index_type,
				'columns' => []
			];
		}

		$indexes[$index_name]['columns'][] = $col_name;
	}

	foreach ($indexes as $index_name => $data) {
		$columns = $data['columns'];
		$index_type = $data['type'];
		$unique = $data['unique'];

		if ($mode === 'encrypt' && in_array($field, $columns)) {
			$new_columns = array_map(fn($col) => ($col === $field ? $field.'_hash' : $col), $columns);
		} elseif ($mode === 'decrypt' && in_array($field.'_hash', $columns)) {
			$new_columns = array_map(fn($col) => ($col === $field.'_hash' ? $field : $col), $columns);
		} else {
			continue;
		}

		$conn->exec("ALTER TABLE ".$table." DROP INDEX ".$index_name);

		$cols_sql = implode(", ", $new_columns);
		$sql = "ALTER TABLE ".$table." ADD ";

		if ($unique) $sql .= "UNIQUE ";
		elseif (strtoupper($index_type) === 'FULLTEXT') $sql .= "FULLTEXT ";
		elseif (strtoupper($index_type) === 'SPATIAL') $sql .= "SPATIAL ";

		$sql .= "INDEX ".$index_name." (".$cols_sql.")";
		$conn->exec($sql);

	}
}

function cron_token() {
	global $conn;
	
	$sql = "SELECT value FROM settings_options WHERE title = 'cron_token' LIMIT 1";
  $result = $conn->prepare($sql);
  $result->execute();

	if ($arr = $result->fetch()) {
		return $arr['value'];
	}
	
	$token = bin2hex(random_bytes(32));
	
	$sql = "INSERT INTO settings_options SET value = :value, title = 'cron_token', c_public = '1' ";
  $result = $conn->prepare($sql);
  $result->bindValue(':value', $token, PDO::PARAM_STR);
  $result->execute();
  
  return $token;
}

function get_encryption_ini($module, $frontend = false) {
  static $cache = [];

  if (isset($cache[$module])) return $cache[$module];

  $ini_path = "config/".$module."_encrypt.ini";
  if ($frontend === true) $ini_path = "comator/".$ini_path;
  if (!file_exists($ini_path)) return null;

  $data = parse_ini_file($ini_path, true);

  $cache[$module] = $data['encrypt'];
  return $cache[$module];
}

function decrypt_field($arr, $field, $encryption_key) {
	$hash_field = $field.'_hash';
	$plain_field = $field.'_plain';

	if (isset($arr[$plain_field])) {
		return $arr[$plain_field];
	}
	if (isset($arr[$hash_field]) && isset($arr[$field])) {
		return decrypt_value($arr[$field], $encryption_key);
	}
	return $arr[$field] ?? null;
}

function append_encrypted_field(string &$sql, array &$params, string $table, string $field, $value, ?array $ini = null, bool &$enc_column = true, bool $encrypt = true): void {
	if ($encrypt && $ini && check_column($table, $field."_hash")){

		$enc_column = true;
		
		$enc_key = $ini['encryption_key'] ?? null;
		$pepper = $ini['pepper'] ?? null;
	
		$sql .= $field." = :".$field.", ".$field."_hash = :".$field."_hash, ";
		$params[":".$field] = encrypt_value($value, $enc_key);
		$params[":".$field."_hash"] = hash_value($value, $pepper);
	
		if (check_column($table, $field."_plain")) {
			$sql .= $field."_plain = :".$field."_plain, ";
			$params[":".$field."_plain"] = $value;
		}
	} else {
		$sql .= $field." = :".$field.", ";
		$params[":".$field] = $value;
	}
}

function csrf_token() {
	if (session_status() === PHP_SESSION_NONE) session_start();
	if (!isset($_SESSION['csrf_token'])) {
		$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
	}
	return $_SESSION['csrf_token'];
}

function csrf_check() {
	if (session_status() === PHP_SESSION_NONE) session_start();
	if ($_SERVER['REQUEST_METHOD'] === 'POST') {
		if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']){
			unset($_SESSION['backend']);
			$current_path = $_SERVER['SCRIPT_NAME'];

			if (strpos($current_path, '/comator/') === 0) {
				header("Location: /comator/index.php?token=invalid");
			} else {
				header("Location: /index.php?token=invalid");
			}
			exit;
		}
	}
}
