<?php

// Validacion de token

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { // Recorre todos los caracteres (siempre) y retorna true or false
        $_SESSION['flash_error'] = 'Acción inválida.';
        header('Location: index.php?opt=inicio_operador');
        exit;
    }
}

// Requiero helper que contiene métodos para encriptar y desencriptar contraseñas

require_once __DIR__ . '/../helpers/crypto.php';

// Requiero modelo de configuración

require __DIR__ . '/../models/configuracionModel.php';
$configuracionmodel = new configuracionModel();

// Validar sesión

if (!isset($_SESSION['user'])) {
    header("Location: index.php?opt=login_operador");
    exit;
}

$user = $_SESSION['user']; // Defino el array del usuario dentro de una variable
$rol = $user['rol']; // Defino el rol dentro de la variable
$esAdmin = ($rol === 'admin'); // Variable booleana, true = admin

// Verifico rol del usuarios (solo se permite admin)

if (!$esAdmin) {
    header("Location: index.php?opt=inicio_operador");
    exit;
}

$opt = $_GET['opt'] ?? null;

// Manejo de opt

switch ($opt) {

    // OBTENER CONFIGURACIÓN

    case 'configuracion':

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            $configuracion = $configuracionmodel->obtenerConfiguracion();

            // Desencriptación de contraseña emisor

            if (isset($configuracion['contrasenia_emisor'])) {
                $configuracion['contrasenia_emisor_formateada'] = decryptData($configuracion['contrasenia_emisor']);
            } else {
                $configuracion['contrasenia_emisor_formateada'] = 'Sin Setear';
            }

            // Saneamiento de email emisor

            if (isset($configuracion['email_emisor'])) {
                $configuracion['email_emisor'] = $configuracion['email_emisor'];
            } else {
                $configuracion['email_emisor'] = 'Sin Setear';
            }

            // Validaciones

            if (empty($configuracion)) {
                $_SESSION['flash_error'] = 'Ocurrió un error al cargar la configuración.';
                header("Location: index.php?opt=configuracion");
                exit;
            }

            // Saneamiento de fecha

            if (!empty($configuracion['inicio_act'])) {
                $dt = new DateTime($configuracion['inicio_act']);
                $configuracion['inicio_act_formateada'] = $dt->format('d/m/Y');
            } else {
                $configuracion['inicio_act_formateada'] = '-';
            }

            ob_start();
            require_once __DIR__ . '/../views/configuracion/configuracionView.php';
            return ob_get_clean();
        }

    // ACTUALIZAR CONFIGURACIÓN

    case 'actualizar_config':

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {

            $configuracion = [

                'nombre' => trim($_POST['nombre'] ?? ''),
                'direccion' => trim($_POST['direccion'] ?? ''),
                'ciudad' => trim($_POST['ciudad'] ?? ''),
                'codigo_postal' => trim($_POST['codigo_postal'] ?? ''),
                'provincia' => trim($_POST['provincia'] ?? ''),
                'telefono' => trim($_POST['telefono'] ?? ''),
                'email' => trim($_POST['email'] ?? ''),
                'cond_iva' => trim($_POST['cond_iva'] ?? 'responsable_inscripto'),
                'cuit' => ($_POST['cuit_1'] ?? '') . ($_POST['cuit_2'] ?? '') . ($_POST['cuit_3'] ?? ''),
                'iva' => $_POST['iva'] ?? 21,
                'hora_apertura_maniana' => trim($_POST['hora_apertura_maniana'] ?? ''),
                'hora_cierre_maniana' => trim($_POST['hora_cierre_maniana'] ?? ''),
                'hora_apertura_tarde' => trim($_POST['hora_apertura_tarde'] ?? ''),
                'hora_cierre_tarde' => trim($_POST['hora_cierre_tarde'] ?? ''),
                'mail_automatico' => isset($_POST['mail_automatico']) ? 1 : 0,
                'cargo_cancelacion_servicio' => $_POST['cargo_cancelacion_servicio'] ?? 0,
                'email_emisor' => trim($_POST['email_emisor'] ?? ''),
                'contrasenia_emisor' => trim($_POST['contrasenia_emisor'] ?? ''),
            ];

            $errores = [];

            // Validaciones

            // NOMBRE

            if ($configuracion['nombre'] === '') {
                $errores[] = "El nombre no puede estar vacío.";
            } else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóú0-9\s\.\-]{2,100}$/', $configuracion['nombre'])) {
                $errores[] = "El nombre contiene caracteres inválidos.";
            } else if (strlen($configuracion['nombre']) < 2) {
                $errores[] = "El nombre debe tener al menos 2 caracteres.";
            } else if (strlen($configuracion['nombre']) > 50) {
                $errores[] = "El nombre no puede superar los 50 caracteres.";
            }

            // DIRECCIÓN

            if ($configuracion['direccion'] === '') {
                $errores[] = "La dirección no puede estar vacía.";
            } else if (strlen($configuracion['direccion']) < 3) {
                $errores[] = "La dirección debe tener al menos 3 caracteres.";
            } else if (strlen($configuracion['direccion']) > 100) {
                $errores[] = "La dirección no puede superar los 100 caracteres.";
            }

            // CIUDAD

            if ($configuracion['ciudad'] === '') {
                $errores[] = "La ciudad no puede estar vacía.";
            } else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóúñÑ\s]{2,100}$/', $configuracion['ciudad'])) {
                $errores[] = "La ciudad solo puede contener letras y espacios.";
            }

            // CODIGO POSTAL

            if ($configuracion['codigo_postal'] === '') {
                $errores[] = "El código postal no puede estar vacío.";
            } else if (!preg_match('/^[0-9]{4}$/', $configuracion['codigo_postal'])) {
                $errores[] = "El código postal debe tener 4 dígitos.";
            }

            // PROVINCIA

            if ($configuracion['provincia'] === '') {
                $errores[] = "La provincia no puede estar vacía.";
            } else if (!preg_match('/^[A-Za-zÁÉÍÓÚáéíóúñÑ\s]{2,100}$/', $configuracion['provincia'])) {
                $errores[] = "La provincia contiene caracteres inválidos.";
            }

            // TELÉFONO

            if ($configuracion['telefono'] === '') {
                $errores[] = "El teléfono no puede estar vacío.";
            } else if (!preg_match('/^[0-9]{10}$/', $configuracion['telefono'])) {
                $errores[] = "El teléfono debe tener 10 dígitos.";
            }

            // EMAIL

            if ($configuracion['email'] === '') {
                $errores[] = "El email no puede estar vacío.";
            } else if (!filter_var($configuracion['email'], FILTER_VALIDATE_EMAIL)) {
                $errores[] = "Formato de email inválido.";
            } else if (strlen($configuracion['email']) > 100) {
                $errores[] = "El email no puede superar los 100 caracteres.";
            }

            // CONDICIÓN_IVA

            $condicionesValidas = [
                'consumidor_final',
                'responsable_inscripto',
                'monotributo'
            ];

            if (!in_array($configuracion['cond_iva'], $condicionesValidas)) {
                $errores[] = "Condición de IVA inválida.";
            }

            // CUIT

            if (!preg_match('/^\d{10,11}$/', $configuracion['cuit'])) {
                $errores[] = 'CUIT inválido. Debe contener solo números.';
            }

            // IVA

            if (!is_numeric($configuracion['iva'])) {
                $errores[] = "El IVA debe ser numérico.";
            }

            // HORA DE APERTURA Y CIERRE

            if ($configuracion['hora_apertura_maniana'] && $configuracion['hora_cierre_maniana']) {

                if ($configuracion['hora_apertura_maniana'] >= $configuracion['hora_cierre_maniana']) {
                    $errores[] = "El horario de apertura debe ser menor al de cierre.";
                }

            }

            if ($configuracion['hora_apertura_tarde'] && $configuracion['hora_cierre_tarde']) {

                if ($configuracion['hora_apertura_tarde'] >= $configuracion['hora_cierre_tarde']) {
                    $errores[] = "El horario de apertura debe ser menor al de cierre.";
                }

            }

            // CARGO POR CANCELACIÓN DE SERVICIO

            if (!is_numeric($configuracion['cargo_cancelacion_servicio'])) {
                $errores[] = "El cargo por cancelación debe ser numérico.";
            }

            // EMAIL EMISOR

            if ($configuracion['email_emisor'] === '') {
                $errores[] = "El email no puede estar vacío.";
            } else if (!filter_var($configuracion['email_emisor'], FILTER_VALIDATE_EMAIL)) {
                $errores[] = "Formato de email inválido.";
            } else if (strlen($configuracion['email_emisor']) > 100) {
                $errores[] = "El email no puede superar los 100 caracteres.";
            }

            // CONTRASEÑA EMISOR

            if (strlen($configuracion['contrasenia_emisor']) > 100) {
                $errores[] = "Contraseña demasiado larga.";
            }

            if (!empty($errores)) {
                $_SESSION['flash_error'] = implode('<br>', $errores); // Se guarda en $_SESSION el error
                header("Location: index.php?opt=configuracion"); 
                exit;
            }

            // ENCRIPTACION DE CONTRASEÑA

            if ($configuracion['contrasenia_emisor'] !== '') {
                $passLimpia = str_replace(' ', '', $configuracion['contrasenia_emisor']);
                $configuracion['contrasenia_emisor'] = encryptData($passLimpia);
            }

            // Actualizamos datos de configuración

            if ($configuracionmodel->actualizarConfiguracion($configuracion)) {
                $_SESSION['flash_success'] = 'Configuración actualizada correctamente.';
                header("Location: index.php?opt=configuracion");
                exit;
            } else {
                $_SESSION['flash_error'] = 'Error al actualizar la configuración.';
                header("Location: index.php?opt=configuracion");
                exit;
            }
        }

    // GENERAR BACKUP

    case 'generar_backup':

        // Obtenemos desde donde viene la petición (puede ser backup automático)

        $return = $_GET['from'] ?? 'backups';

        $backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');

        $fecha = date('Y-m-d_H-i-s');
        $archivo = "backup_$fecha.sql"; // Generación de nombre de archivo con extensión
        $rutaBackup = $backupDir . $archivo; // Generación de ruta completa de archivo backup

        // Datos de conexión

        $rutaBackup = escapeshellarg($rutaBackup); // Permite omitir espacios o caracteres no deseados (puede romper ruta o comando)
        $host = escapeshellarg($_ENV['DB_HOST']);
        $usuario = escapeshellarg($_ENV['DB_USER']);
        $database = escapeshellarg($_ENV['DB_NAME']);
        $password = escapeshellarg($_ENV['DB_PASSWORD']);
        
        // Comando pg_dump
    
        $comando = "PGPASSWORD=$password pg_dump --clean --if-exists --no-owner -h $host -U $usuario -d $database > $rutaBackup"; // Guardamos el comando a ejecutar mediante pg_dump

        exec($comando, $output, $resultado); // Lo ejecutamos

        if ($resultado === 0) { // Entra al if solo si el (exec) dio como resultado 0 (éxito) en la variable $resultado

            // Limitar cantidad de backups

            $maxBackups = 4;

            $archivos = glob($backupDir . '*.sql'); // Permite obtener todos los archivos ubicados en esa ruta

            if (count($archivos) > $maxBackups) { // Contamos la cantidad de archivos (comparando con la cantidad máxima definida)

                usort($archivos, function ($a, $b) {
                    return filemtime($a) - filemtime($b);
                }); // Se ordenan en base a la fecha de modificación de mas antiguo a mas nuevo

                while (count($archivos) > $maxBackups) {
                    $archivoEliminar = array_shift($archivos); // Se elimina el archivo del array
                    unlink($archivoEliminar); // Se elimina fisicamente el archivo
                }
            }

            if (isset($_GET['auto'])) {

                $_SESSION['flash_success'] = "Copia de seguridad automática generada con éxito.";
            } else {
                
                $_SESSION['flash_success'] = "Backup generado correctamente.";
            }

        } else {

            $_SESSION['flash_error'] = "Error al generar el backup.";
        }

        header("Location: index.php?opt=$return");
        exit;

    // LISTAR BACKUPS

    case 'backups':

        $backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');

        $archivos = glob($backupDir . '*.sql');

        $backups = [];
        $totalSize = 0;

        $ultimoBackup = null;

        if ($archivos) {

            usort($archivos, function ($a, $b) {
                return filemtime($b) <=> filemtime($a);
            });

            $ultimoBackup = date('d/m/Y H:i', filemtime($archivos[0])); // Guardamos el archivo mas reciente para informar en la vista

            foreach ($archivos as $archivo) {

                $size = filesize($archivo); // Obtenemos el tamaño total del archivo

                $backups[] = [
                    'nombre' => basename($archivo), // Obtenemos nombre de archivo
                    'fecha' => date('d/m/Y H:i', filemtime($archivo)), // Obtenemos la fecha del archivo
                    'size' => round($size / 1024, 2) . ' KB' // Obtenemos el tamaño del archivo en KB
                ];

                $totalSize += $size; // Acumulamos el tamaño de los archivos para obtener el total
            }
        }

        $totalSize = round($totalSize / 1024 / 1024, 2); // Total utilizado en MB

        ob_start();
        require __DIR__ . '/../views/configuracion/buckupsView.php';
        return ob_get_clean();

    // DESCARGAR BACKUP

    case 'descargar_backup':

        $file = basename($_GET['file']);

        $backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');
        $ruta = $backupDir . $file;

        if (!file_exists($ruta)) {
            header("Location: index.php?opt=backups");
            exit;
        }

        header('Content-Type: application/sql'); // Indica el tipo de contenido del archivo (SQL en este caso)
        header('Content-Disposition: attachment; filename="' . $file . '"'); // Fuerza la descarga del archivo en lugar de mostrarlo en el navegador y define el nombre con el que se va a guardar
        header('Content-Length: ' . filesize($ruta)); // Informa el tamaño del archivo (mejora la descarga/progreso)

        readfile($ruta); // Envía el contenido del archivo al navegador
        exit;

    // ELIMINAR BACKUP

    case 'eliminar_backup':

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {

            $backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');

            $archivo = basename($_POST['file']); // Evita rutas maliciosas

            $rutaArchivo = $backupDir . $archivo;

            if (file_exists($rutaArchivo)) {

                unlink($rutaArchivo);

                $_SESSION['flash_success'] = "Backup eliminado correctamente.";

            } else {

                $_SESSION['flash_error'] = "El archivo no existe.";

            }

            header("Location: index.php?opt=backups");
            exit;
        }

    // RESTAURAR BACKUP

    case 'restaurar_backup':

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {

            $backupDir = $_ENV['BACKUP_PATH'] ?? (__DIR__ . '/../backups/');

            $archivo = basename($_POST['file']);
            $rutaBackup = $backupDir . $archivo;

            if (!file_exists($rutaBackup)) {

                $_SESSION['flash_error'] = "El archivo de backup no existe.";
                header("Location: index.php?opt=backups");
                exit;

            }

            $host = escapeshellarg($_ENV['DB_HOST']);
            $usuario = escapeshellarg($_ENV['DB_USER']);
            $database = escapeshellarg($_ENV['DB_NAME']);
            $password = escapeshellarg($_ENV['DB_PASSWORD']);

            // 1. BACKUP AUTOMÁTICO PREVIO

            $backupSeguridad = $backupDir . 'auto_pre_restore_' . date('Y-m-d_H-i-s') . '.sql';
            $backupSeguridadEscaped = escapeshellarg($backupSeguridad);

            $comandoBackup = "PGPASSWORD=$password pg_dump --clean --if-exists --no-owner -h $host -U $usuario -d $database > $backupSeguridadEscaped";

            exec($comandoBackup, $outBackup, $resultadoBackup);

            if ($resultadoBackup !== 0) {

                $_SESSION['flash_error'] = "No se pudo crear el backup de seguridad antes de restaurar.";
                header("Location: index.php?opt=backups");
                exit;

            }

            // 2. RESTAURAR COPIA DE SEGURIDAD SELECCIONADA

            $rutaBackupEscaped = escapeshellarg($rutaBackup);

            $comandoRestore = "PGPASSWORD=$password psql -h $host -U $usuario -d $database < $rutaBackupEscaped";

            exec($comandoRestore, $output, $resultadoRestore);

            if ($resultadoRestore === 0) {

                $_SESSION['flash_success'] = "Backup restaurado correctamente. Se creó una copia de seguridad previa.";

            } else {

                $_SESSION['flash_error'] = "Error al restaurar el backup.";

            }

            header("Location: index.php?opt=backups");
            exit;
        }
}