<?php
include(__DIR__ . '/db.php');
include(__DIR__ . '/table.php');//parse config options
//parse config options
try {
	@$config_ini = parse_ini_file("./config.ini");
} catch (Exception $e) {
	@$config_ini = parse_ini_file("../config.ini");
}

if (@$config_ini['debug'] == 1 ){
	ini_set('display_errors', 1);
	ini_set('display_startup_errors', 1);
	error_reporting(E_ALL);
}else{
	ini_set('display_errors', 0);
}

$status = session_status();
if($status == PHP_SESSION_NONE){
	session_start();
}else
if($status == PHP_SESSION_DISABLED){
	//Sessions are not available
}else
if($status == PHP_SESSION_ACTIVE){
	//Destroy current and start new one
	session_destroy();
	session_start();
}


function generate_token() {
	if(!isset($_SESSION["ftg"])) {
		$token = random_bytes(64);
		$_SESSION["ftg"] = $token;
	} else {
		$token = $_SESSION["ftg"];
	}
	return $token;
}

function createTables($tables, $dbLoc) {
	try {
		$db = new SQLite3($dbLoc);
	} catch (Exception $e) {
		$db = new SQLite3('.db.db');
	}

	if (!$db) {
		die("Error connecting to the database");
	}

	foreach ($tables as $tableName => $columns) {
		$sql = "CREATE TABLE IF NOT EXISTS $tableName (";
		foreach ($columns as $columnName => $columnType) {
			$sql .= "$columnName $columnType, ";
		}
		$sql = rtrim($sql, ', ');
		$sql .= ");";
		if ($db->exec($sql)) {
		} else {
			echo "Error creating table: " . $db->lastErrorMsg();
		}
	}
	$db->close();
}


createTables($tables, $dbPath);

class SQLiteWrapper {
	private $db;

	public function __construct($dbLoc) {
		
		try {
			$this->db = new SQLite3($dbLoc);
		} catch (Exception $e) {
			$this->db = new SQLite3('.db.db');
		}
		if (!$this->db) {
			die("Error: Unable to open database.");
		}
	}

	public function select($tableName, $columns = "*", $where = "", $orderBy = "", $placeholders = array()) {
		$query = "SELECT $columns FROM $tableName";
		if (!empty($where)) {
			$query .= " WHERE $where";
		}
		if (!empty($orderBy)) {
			$query .= " ORDER BY $orderBy";
		}
	
		$stmt = $this->db->prepare($query);
	
		foreach ($placeholders as $key => $value) {
			$stmt->bindValue($key, $value);
		}
	
		$result = $stmt->execute();
	
		$data = array();
		while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
			$data[] = $row;
		}
		return $data;
	}
	
	public function insert($tableName, $data) {
		$columns = implode(', ', array_keys($data));
		$placeholders = ':' . implode(', :', array_keys($data));
		$query = "INSERT INTO $tableName ($columns) VALUES ($placeholders)";
	
		$stmt = $this->db->prepare($query);
	
		foreach ($data as $key => $value) {
			$stmt->bindValue(':' . $key, $value);
		}
	
		return $stmt->execute();
	}
	
	public function update($tableName, $data, $where = "", $placeholders = array()) {
		$setValues = [];
		foreach ($data as $column => $value) {
			$setValues[] = "$column = :$column";
		}
		$setClause = implode(', ', $setValues);
		$query = "UPDATE $tableName SET $setClause";
		if (!empty($where)) {
			$query .= " WHERE $where";
		}
		
		$stmt = $this->db->prepare($query);
	
		foreach ($data as $key => $value) {
			$stmt->bindValue(':' . $key, $value);
		}
	
		foreach ($placeholders as $key => $value) {
			$stmt->bindValue($key, $value);
		}
	
		return $stmt->execute();
	}


	public function delete($tableName, $where = "", $placeholders = array()) {
		$query = "DELETE FROM $tableName";
		if (!empty($where)) {
			$query .= " WHERE $where";
		}
	
		$stmt = $this->db->prepare($query);
	
		foreach ($placeholders as $key => $value) {
			$stmt->bindValue($key, $value);
		}
	
		return $stmt->execute();
	}


	public function insertIfEmpty($tableName, $data) {
		$isEmpty = $this->isEmptyTable($tableName);

		if ($isEmpty) {
			$columns = implode(', ', array_keys($data));
			$values = "'" . implode("', '", $data) . "'";
			$query = "INSERT INTO $tableName ($columns) VALUES ($values)";
			return $this->db->exec($query);
		} else {
			return false;
		}
	}

	private function isEmptyTable($tableName) {
		$result = $this->db->query("SELECT COUNT(*) as count FROM $tableName");
		$row = $result->fetchArray(SQLITE3_ASSOC);
		return ($row['count'] == 0);
	}

	public function getLastInsertId() {
		return $this->db->lastInsertRowID();
	}

	public function close() {
		$this->db->close();
	}
	
	// Insertar o actualizar configuración
	public function upsertConfig($key, $value) {
		$existing = $this->select('panel_config', '*', 'config_key = :key', '', [':key' => $key]);
		if (!empty($existing)) {
			return $this->update('panel_config', ['config_value' => $value], 'config_key = :key', [':key' => $key]);
		} else {
			return $this->insert('panel_config', ['config_key' => $key, 'config_value' => $value]);
		}
	}
	
	// Obtener configuración
	public function getConfig($key, $default = '') {
		$result = $this->select('panel_config', 'config_value', 'config_key = :key', '', [':key' => $key]);
		return !empty($result) ? $result[0]['config_value'] : $default;
	}
	
	// Contar registros
	public function count($tableName, $where = "", $placeholders = array()) {
		$query = "SELECT COUNT(*) as total FROM $tableName";
		if (!empty($where)) {
			$query .= " WHERE $where";
		}
		$stmt = $this->db->prepare($query);
		foreach ($placeholders as $key => $value) {
			$stmt->bindValue($key, $value);
		}
		$result = $stmt->execute();
		$row = $result->fetchArray(SQLITE3_ASSOC);
		return $row['total'];
	}
}


class Encryption {

    public static function run($input) {
    	$main = bin2hex($input);
    	$output = strrev($main);
    	return $output;
	} 
}

class calllink {

	public static function run($api_link){
        $returnData = "0";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $api_link);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        $result = json_decode(curl_exec($ch));
        if (!empty($result)) {
            $returndata = $result;
            return ["result" => "success", "data" => $returndata];
        }
	}
}


////Get User IP
function real_ip() {
	$ip = 'undefined';
	if (isset($_SERVER)) {
		$ip = $_SERVER['REMOTE_ADDR'];
		if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		elseif (isset($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];
	} else {
		$ip = getenv('REMOTE_ADDR');
		if (getenv('HTTP_X_FORWARDED_FOR')) $ip = getenv('HTTP_X_FORWARDED_FOR');
		elseif (getenv('HTTP_CLIENT_IP')) $ip = getenv('HTTP_CLIENT_IP');
	}
	$ip = htmlspecialchars($ip, ENT_QUOTES, 'UTF-8');
	return $ip;
}

// Función para obtener el usuario actual
function getCurrentUser($db) {
	if (!isset($_SESSION['name'])) {
		return null;
	}
	$userData = $db->select('user', '*', 'username = :username', '', [':username' => $_SESSION['name']]);
	return !empty($userData) ? $userData[0] : null;
}

// Función para verificar si el usuario es admin
function isAdmin($db) {
	$user = getCurrentUser($db);
	return $user && $user['role'] === 'admin';
}

// Función para verificar si el usuario es reseller
function isReseller($db) {
	$user = getCurrentUser($db);
	return $user && $user['role'] === 'reseller';
}

// Función para obtener créditos disponibles
function getAvailableCredits($db, $userId) {
	$user = $db->select('user', 'credits', 'id = :id', '', [':id' => $userId]);
	return !empty($user) ? $user[0]['credits'] : 0;
}

// Función para restar créditos (con auditoría mejorada)
function deductCredits($db, $userId, $amount, $description, $performedBy = null) {
	$currentCredits = getAvailableCredits($db, $userId);
	
	if ($currentCredits < $amount) {
		return false;
	}
	
	$newCredits = $currentCredits - $amount;
	$db->update('user', ['credits' => $newCredits], 'id = :id', [':id' => $userId]);
	
	// Registrar en el log de créditos
	$logData = [
		'user_id' => $userId,
		'amount' => $amount,
		'action' => 'subtract',
		'description' => $description,
		'performed_by' => $performedBy ?? $userId,
	];
	$db->insert('credit_logs', $logData);
	
	return true;
}

// Función para añadir créditos (con auditoría mejorada)
function addCredits($db, $userId, $amount, $description, $performedBy = null) {
	$currentCredits = getAvailableCredits($db, $userId);
	$newCredits = $currentCredits + $amount;
	$db->update('user', ['credits' => $newCredits], 'id = :id', [':id' => $userId]);
	
	// Registrar en el log de créditos
	$logData = [
		'user_id' => $userId,
		'amount' => $amount,
		'action' => 'add',
		'description' => $description,
		'performed_by' => $performedBy ?? $userId,
	];
	$db->insert('credit_logs', $logData);
	
	return true;
}

// Función para obtener clientes de un usuario (reseller o admin)
function getUserClients($db, $userId) {
	$user = getCurrentUser($db);
	
	if ($user['role'] === 'admin') {
		// El admin ve todos los clientes
		return $db->select('menualuser', '*', '', '');
	} else {
		// El reseller solo ve sus propios clientes
		return $db->select('menualuser', '*', 'owner_id = :owner_id', '', [':owner_id' => $userId]);
	}
}

// Funciones de configuración del panel
function getPanelConfig($db, $key, $default = '') {
	return $db->getConfig($key, $default);
}

function setPanelConfig($db, $key, $value) {
	return $db->upsertConfig($key, $value);
}

// Obtener nombre del panel
function getPanelName($db) {
	return getPanelConfig($db, 'panel_name', 'Panel Creador de Cuentas');
}

// Obtener contacto del panel
function getPanelContact($db) {
	return getPanelConfig($db, 'panel_contact', 'Contacta al administrador');
}

// Obtener logo del panel
function getPanelLogo($db) {
	return getPanelConfig($db, 'panel_logo', './img/login_logo.png');
}

// ============================================
// FUNCIONES DE AUDITORÍA Y REGISTRO
// ============================================

/**
 * Registrar una actividad en el log de auditoría
 * 
 * @param object $db - Instancia de la base de datos
 * @param int $userId - ID del usuario que realiza la acción
 * @param string $actionType - Tipo de acción: 'create', 'update', 'delete', 'login', 'logout'
 * @param string $entityType - Tipo de entidad: 'client', 'reseller', 'dns', 'config'
 * @param int $entityId - ID de la entidad afectada
 * @param string $entityName - Nombre o identificador de la entidad
 * @param string $details - Detalles adicionales de la acción (JSON o texto)
 */
function logActivity($db, $userId, $actionType, $entityType, $entityId, $entityName, $details = '') {
	$logData = [
		'user_id' => $userId,
		'action_type' => $actionType,
		'entity_type' => $entityType,
		'entity_id' => $entityId,
		'entity_name' => $entityName,
		'details' => $details,
		'ip_address' => real_ip(),
	];
	
	return $db->insert('activity_logs', $logData);
}

/**
 * Registrar creación de cliente
 */
function logClientCreated($db, $userId, $clientId, $clientUsername, $duration, $credits) {
	$details = json_encode([
		'duration' => $duration,
		'credits_used' => $credits,
		'action' => 'Cuenta creada'
	]);
	return logActivity($db, $userId, 'create', 'client', $clientId, $clientUsername, $details);
}

/**
 * Registrar eliminación de cliente
 */
function logClientDeleted($db, $userId, $clientId, $clientUsername) {
	$details = json_encode([
		'action' => 'Cuenta eliminada'
	]);
	return logActivity($db, $userId, 'delete', 'client', $clientId, $clientUsername, $details);
}

/**
 * Registrar modificación de cliente
 */
function logClientUpdated($db, $userId, $clientId, $clientUsername, $changes) {
	$details = json_encode([
		'changes' => $changes,
		'action' => 'Cuenta modificada'
	]);
	return logActivity($db, $userId, 'update', 'client', $clientId, $clientUsername, $details);
}

/**
 * Registrar creación de revendedor
 */
function logResellerCreated($db, $userId, $resellerId, $resellerUsername, $initialCredits) {
	$details = json_encode([
		'initial_credits' => $initialCredits,
		'action' => 'Revendedor creado'
	]);
	return logActivity($db, $userId, 'create', 'reseller', $resellerId, $resellerUsername, $details);
}

/**
 * Registrar eliminación de revendedor
 */
function logResellerDeleted($db, $userId, $resellerId, $resellerUsername) {
	$details = json_encode([
		'action' => 'Revendedor eliminado'
	]);
	return logActivity($db, $userId, 'delete', 'reseller', $resellerId, $resellerUsername, $details);
}

/**
 * Registrar asignación de créditos
 */
function logCreditsAssigned($db, $userId, $targetUserId, $targetUsername, $amount, $newBalance) {
	$details = json_encode([
		'amount' => $amount,
		'new_balance' => $newBalance,
		'action' => 'Créditos asignados'
	]);
	return logActivity($db, $userId, 'credit_add', 'reseller', $targetUserId, $targetUsername, $details);
}

/**
 * Obtener historial de actividades
 * 
 * @param object $db - Instancia de la base de datos
 * @param int|null $userId - Filtrar por usuario (null para todos)
 * @param string|null $entityType - Filtrar por tipo de entidad
 * @param string|null $actionType - Filtrar por tipo de acción
 * @param int $limit - Límite de registros
 */
function getActivityLogs($db, $userId = null, $entityType = null, $actionType = null, $limit = 100) {
	$where = "";
	$params = [];
	$conditions = [];
	
	if ($userId !== null) {
		$conditions[] = "user_id = :user_id";
		$params[':user_id'] = $userId;
	}
	
	if ($entityType !== null) {
		$conditions[] = "entity_type = :entity_type";
		$params[':entity_type'] = $entityType;
	}
	
	if ($actionType !== null) {
		$conditions[] = "action_type = :action_type";
		$params[':action_type'] = $actionType;
	}
	
	if (!empty($conditions)) {
		$where = implode(' AND ', $conditions);
	}
	
	return $db->select('activity_logs', '*', $where, 'date DESC', $params);
}

/**
 * Obtener historial de créditos
 */
function getCreditLogs($db, $userId = null, $limit = 100) {
	$where = "";
	$params = [];
	
	if ($userId !== null) {
		$where = "user_id = :user_id";
		$params[':user_id'] = $userId;
	}
	
	return $db->select('credit_logs', '*', $where, 'date DESC', $params);
}

/**
 * Obtener estadísticas de auditoría
 */
function getAuditStats($db, $userId = null) {
	$params = [];
	$userFilter = "";
	
	if ($userId !== null) {
		$userFilter = "user_id = :user_id";
		$params[':user_id'] = $userId;
	}
	
	// Total de clientes creados
	$clientsCreated = $db->count('activity_logs', 
		($userFilter ? $userFilter . " AND " : "") . "action_type = 'create' AND entity_type = 'client'", 
		$params);
	
	// Total de clientes eliminados
	$clientsDeleted = $db->count('activity_logs', 
		($userFilter ? $userFilter . " AND " : "") . "action_type = 'delete' AND entity_type = 'client'", 
		$params);
	
	// Total de créditos asignados
	$creditLogs = $db->select('credit_logs', 'SUM(amount) as total', 
		($userFilter ? "user_id = :user_id AND " : "") . "action = 'add'", '', $params);
	$totalCreditsAdded = $creditLogs[0]['total'] ?? 0;
	
	// Total de créditos usados
	$creditUsed = $db->select('credit_logs', 'SUM(amount) as total', 
		($userFilter ? "user_id = :user_id AND " : "") . "action = 'subtract'", '', $params);
	$totalCreditsUsed = $creditUsed[0]['total'] ?? 0;
	
	return [
		'clients_created' => $clientsCreated,
		'clients_deleted' => $clientsDeleted,
		'credits_added' => $totalCreditsAdded,
		'credits_used' => $totalCreditsUsed,
	];
}

/**
 * Obtener nombre de usuario por ID
 */
function getUsernameById($db, $userId) {
	$user = $db->select('user', 'username', 'id = :id', '', [':id' => $userId]);
	return !empty($user) ? $user[0]['username'] : 'Sistema';
}

/**
 * Formatear tipo de acción para mostrar
 */
function formatActionType($actionType) {
	$types = [
		'create' => 'Creación',
		'update' => 'Modificación',
		'delete' => 'Eliminación',
		'credit_add' => 'Créditos Agregados',
		'credit_subtract' => 'Créditos Descontados',
		'login' => 'Inicio de Sesión',
		'logout' => 'Cierre de Sesión',
	];
	return $types[$actionType] ?? $actionType;
}

/**
 * Formatear tipo de entidad para mostrar
 */
function formatEntityType($entityType) {
	$types = [
		'client' => 'Cliente',
		'reseller' => 'Revendedor',
		'dns' => 'DNS',
		'config' => 'Configuración',
	];
	return $types[$entityType] ?? $entityType;
}

/**
 * Obtener color de badge según tipo de acción
 */
function getActionBadgeClass($actionType) {
	$classes = [
		'create' => 'badge-success',
		'update' => 'badge-info',
		'delete' => 'badge-danger',
		'credit_add' => 'badge-primary',
		'credit_subtract' => 'badge-warning',
		'login' => 'badge-secondary',
		'logout' => 'badge-secondary',
	];
	return $classes[$actionType] ?? 'badge-secondary';
}
