<?php
/**
 * Helper para el módulo de Control Administrativo
 *
 * Gestiona grupos, items, aplicadores y progreso del control administrativo.
 * También maneja la extracción de comentarios del plugin Discussion.
 *
 * @author NICC
 * @date 2026-01-31
 */

class AdminControlHelper {

    /** @var helper_plugin_sqlite */
    private $sqlite;

    /** @var helper_plugin_sqlite */
    private $sqliteDo;

    /**
     * Constructor
     * @param helper_plugin_sqlite $sqlite Conexión a b3p.sqlite3
     * @param helper_plugin_sqlite $sqliteDo Conexión a do.sqlite3 (opcional)
     */
    public function __construct($sqlite, $sqliteDo = null) {
        $this->sqlite = $sqlite;
        $this->sqliteDo = $sqliteDo;
    }

    // =========================================
    // GRUPOS
    // =========================================

    /**
     * Obtiene todos los grupos activos
     * @return array
     */
    public function getGrupos() {
        $query = "SELECT * FROM admin_control_groups WHERE activo = 1 ORDER BY orden, id";
        $res = $this->sqlite->query($query);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Obtiene un grupo por ID
     * @param int $id
     * @return array|null
     */
    public function getGrupo($id) {
        $query = "SELECT * FROM admin_control_groups WHERE id = ?";
        $res = $this->sqlite->query($query, [$id]);
        $arr = $this->sqlite->res2arr($res);
        return !empty($arr) ? $arr[0] : null;
    }

    /**
     * Crea un nuevo grupo
     * @param string $nombre
     * @param string $descripcion
     * @param int $orden
     * @return int ID del grupo creado
     */
    public function crearGrupo($nombre, $descripcion = '', $orden = 0) {
        $query = "INSERT INTO admin_control_groups (nombre, descripcion, orden) VALUES (?, ?, ?)";
        $this->sqlite->query($query, [$nombre, $descripcion, $orden]);

        $res = $this->sqlite->query("SELECT last_insert_rowid() as id");
        $arr = $this->sqlite->res2arr($res);
        return $arr[0]['id'];
    }

    // =========================================
    // ITEMS (COMPONENTES)
    // =========================================

    /**
     * Obtiene todos los items de un grupo
     * @param int $grupoId
     * @return array
     */
    public function getItemsDeGrupo($grupoId) {
        $query = "SELECT * FROM admin_control_items WHERE grupo_id = ? AND activo = 1 ORDER BY orden, id";
        $res = $this->sqlite->query($query, [$grupoId]);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Obtiene solo items de tipo 'actividad' (los que cuentan para progreso)
     * @param int $grupoId
     * @return array
     */
    public function getActividadesDeGrupo($grupoId) {
        $query = "SELECT * FROM admin_control_items WHERE grupo_id = ? AND activo = 1 AND tipo = 'actividad' ORDER BY orden, id";
        $res = $this->sqlite->query($query, [$grupoId]);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Obtiene items de tipo 'registro' (para exportar comentarios)
     * @param int $grupoId
     * @return array
     */
    public function getRegistrosDeGrupo($grupoId) {
        $query = "SELECT * FROM admin_control_items WHERE grupo_id = ? AND activo = 1 AND tipo = 'registro' ORDER BY orden, id";
        $res = $this->sqlite->query($query, [$grupoId]);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Crea un nuevo item
     * @param int $grupoId
     * @param string $nombre
     * @param string $rutaWiki
     * @param int $orden
     * @param string $tipo 'actividad' o 'registro'
     * @return int
     */
    public function crearItem($grupoId, $nombre, $rutaWiki, $orden = 0, $tipo = 'actividad') {
        $query = "INSERT INTO admin_control_items (grupo_id, nombre, ruta_wiki, orden, tipo) VALUES (?, ?, ?, ?, ?)";
        $this->sqlite->query($query, [$grupoId, $nombre, $rutaWiki, $orden, $tipo]);

        $res = $this->sqlite->query("SELECT last_insert_rowid() as id");
        $arr = $this->sqlite->res2arr($res);
        return $arr[0]['id'];
    }

    // =========================================
    // APLICADORES
    // =========================================

    /**
     * Obtiene todos los aplicadores activos
     * @return array
     */
    public function getAplicadores() {
        $query = "SELECT * FROM admin_control_aplicadores WHERE activo = 1 ORDER BY es_principal DESC, nombre";
        $res = $this->sqlite->query($query);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Obtiene el aplicador principal (la firma)
     * @return array|null
     */
    public function getAplicadorPrincipal() {
        $query = "SELECT * FROM admin_control_aplicadores WHERE es_principal = 1 AND activo = 1 LIMIT 1";
        $res = $this->sqlite->query($query);
        $arr = $this->sqlite->res2arr($res);
        return !empty($arr) ? $arr[0] : null;
    }

    /**
     * Obtiene aplicadores secundarios (trabajadores)
     * @return array
     */
    public function getAplicadoresSecundarios() {
        $query = "SELECT * FROM admin_control_aplicadores WHERE es_principal = 0 AND activo = 1 ORDER BY nombre";
        $res = $this->sqlite->query($query);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Crea un nuevo aplicador
     * @param string $tipo 'firma' o 'trabajador'
     * @param string $nombre
     * @param string $usuarioId username de DokuWiki (solo para trabajadores)
     * @param bool $esPrincipal
     * @param string $paginaDiscusion
     * @return int
     */
    public function crearAplicador($tipo, $nombre, $usuarioId = null, $esPrincipal = false, $paginaDiscusion = null) {
        $query = "INSERT INTO admin_control_aplicadores (tipo, nombre, usuario_id, es_principal, pagina_discusion) VALUES (?, ?, ?, ?, ?)";
        $this->sqlite->query($query, [$tipo, $nombre, $usuarioId, $esPrincipal ? 1 : 0, $paginaDiscusion]);

        $res = $this->sqlite->query("SELECT last_insert_rowid() as id");
        $arr = $this->sqlite->res2arr($res);
        return $arr[0]['id'];
    }

    /**
     * Actualiza la página de discusión de un aplicador
     * @param int $aplicadorId
     * @param string $paginaDiscusion
     */
    public function actualizarPaginaDiscusion($aplicadorId, $paginaDiscusion) {
        $query = "UPDATE admin_control_aplicadores SET pagina_discusion = ? WHERE id = ?";
        $this->sqlite->query($query, [$paginaDiscusion, $aplicadorId]);
    }

    // =========================================
    // PROGRESO
    // =========================================

    /**
     * Obtiene el progreso de un aplicador para todos los items de un grupo
     * @param int $aplicadorId
     * @param int $grupoId
     * @return array
     */
    public function getProgresoAplicador($aplicadorId, $grupoId) {
        $query = "SELECT i.*,
                         COALESCE(p.total_requerimientos, 0) as total_requerimientos,
                         COALESCE(p.requerimientos_terminados, 0) as requerimientos_terminados,
                         COALESCE(p.porcentaje_progreso, 0) as porcentaje_progreso,
                         p.updated_at
                  FROM admin_control_items i
                  LEFT JOIN admin_control_progress p ON i.id = p.item_id AND p.aplicador_id = ?
                  WHERE i.grupo_id = ? AND i.activo = 1 AND i.tipo = 'actividad'
                  ORDER BY i.orden, i.id";
        $res = $this->sqlite->query($query, [$aplicadorId, $grupoId]);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Obtiene el progreso total de un aplicador para un grupo
     * @param int $aplicadorId
     * @param int $grupoId
     * @return array ['total' => int, 'completados' => int, 'porcentaje' => float]
     */
    public function getProgresoTotalAplicador($aplicadorId, $grupoId) {
        $query = "SELECT SUM(COALESCE(p.total_requerimientos, 0)) as total,
                         SUM(COALESCE(p.requerimientos_terminados, 0)) as completados
                  FROM admin_control_items i
                  LEFT JOIN admin_control_progress p ON i.id = p.item_id AND p.aplicador_id = ?
                  WHERE i.grupo_id = ? AND i.activo = 1 AND i.tipo = 'actividad'";
        $res = $this->sqlite->query($query, [$aplicadorId, $grupoId]);
        $arr = $this->sqlite->res2arr($res);

        $total = intval($arr[0]['total']);
        $completados = intval($arr[0]['completados']);
        $porcentaje = $total > 0 ? round(($completados / $total) * 100, 2) : 0;

        return [
            'total' => $total,
            'completados' => $completados,
            'porcentaje' => $porcentaje
        ];
    }

    /**
     * Actualiza el progreso de un item para un aplicador
     * @param int $aplicadorId
     * @param int $itemId
     * @param int $total
     * @param int $terminados
     */
    public function actualizarProgreso($aplicadorId, $itemId, $total, $terminados) {
        $porcentaje = $total > 0 ? round(($terminados / $total) * 100, 2) : 0;

        $query = "INSERT OR REPLACE INTO admin_control_progress
                  (aplicador_id, item_id, total_requerimientos, requerimientos_terminados, porcentaje_progreso, updated_at)
                  VALUES (?, ?, ?, ?, ?, datetime('now'))";
        $this->sqlite->query($query, [$aplicadorId, $itemId, $total, $terminados, $porcentaje]);
    }

    /**
     * Calcula y actualiza el progreso basado en tareas DO de una página
     * @param int $aplicadorId
     * @param int $itemId
     * @param string $rutaWiki
     */
    public function calcularProgresoDesdeDoPlugin($aplicadorId, $itemId, $rutaWiki) {
        if (!$this->sqliteDo) {
            return;
        }

        // Contar total de tareas en la página
        $queryTotal = "SELECT COUNT(*) as total FROM tasks WHERE page = ?";
        $resTotal = $this->sqliteDo->query($queryTotal, [$rutaWiki]);
        $arrTotal = $this->sqliteDo->res2arr($resTotal);
        $total = intval($arrTotal[0]['total']);

        // Contar tareas completadas
        $queryCompletadas = "SELECT COUNT(*) as completadas
                            FROM task_status
                            WHERE page = ? AND msg IN ('Completado', 'No Aplica')";
        $resCompletadas = $this->sqliteDo->query($queryCompletadas, [$rutaWiki]);
        $arrCompletadas = $this->sqliteDo->res2arr($resCompletadas);
        $completadas = intval($arrCompletadas[0]['completadas']);

        $this->actualizarProgreso($aplicadorId, $itemId, $total, $completadas);
    }

    // =========================================
    // EXTRACCIÓN DE COMENTARIOS (DISCUSSION)
    // =========================================

    /**
     * Lee los comentarios de una página con ~~DISCUSSION~~
     * @param string $pageId ej: 'encargos:general'
     * @return array|null
     */
    public function leerComentariosDiscussion($pageId) {
        $file = metaFN($pageId, '.comments');

        if (!file_exists($file)) {
            return null;
        }

        $data = unserialize(io_readFile($file, false));
        return $data;
    }

    /**
     * Cuenta los comentarios visibles de una página
     * @param string $pageId
     * @return int
     */
    public function contarComentarios($pageId) {
        $data = $this->leerComentariosDiscussion($pageId);

        if (!$data || empty($data['comments'])) {
            return 0;
        }

        return intval($data['number']);
    }

    /**
     * Extrae comentarios y los convierte a texto wiki formateado
     * @param string $pageId ej: 'encargos:general5'
     * @return string texto wiki
     */
    public function extraerComentariosATexto($pageId) {
        $data = $this->leerComentariosDiscussion($pageId);

        if (!$data || empty($data['comments'])) {
            return "====== Registros de Cumplimiento ======\n\nSin comentarios registrados.\n";
        }

        $output = "====== Registros de Cumplimiento General ======\n\n";
        $output .= "**Fuente:** [[$pageId]]\n\n";
        $output .= "**Fecha de extracción:** " . date('Y-m-d H:i:s') . "\n\n";
        $output .= "**Total de registros:** " . $data['number'] . "\n\n";
        $output .= "----\n\n";

        $contador = 1;
        foreach ($data['comments'] as $cid => $comment) {
            // Saltar comentarios ocultos
            if (!$comment['show']) continue;

            // Solo procesar comentarios raíz (sin padre)
            if (!empty($comment['parent'])) continue;

            // Obtener datos del usuario
            if (is_array($comment['user'])) {
                $usuario = $comment['user']['name'];
                $usuarioId = $comment['user']['id'];
            } else {
                $usuario = isset($comment['name']) ? $comment['name'] : 'Anónimo';
                $usuarioId = '';
            }

            // Obtener fecha
            if (is_array($comment['date'])) {
                $fecha = date('Y-m-d H:i', $comment['date']['created']);
            } else {
                $fecha = date('Y-m-d H:i', $comment['date']);
            }

            $output .= "=== Registro #$contador ===\n\n";
            $output .= "**Fecha:** $fecha\n\n";
            $output .= "**Usuario:** $usuario" . ($usuarioId ? " ($usuarioId)" : "") . "\n\n";
            $output .= "**Contenido:**\n\n";
            $output .= $comment['raw'] . "\n\n";

            // Procesar respuestas
            if (!empty($comment['replies'])) {
                $output .= "**Respuestas:**\n\n";
                foreach ($comment['replies'] as $rid) {
                    if (isset($data['comments'][$rid]) && $data['comments'][$rid]['show']) {
                        $reply = $data['comments'][$rid];

                        if (is_array($reply['user'])) {
                            $replyUsuario = $reply['user']['name'];
                        } else {
                            $replyUsuario = isset($reply['name']) ? $reply['name'] : 'Anónimo';
                        }

                        if (is_array($reply['date'])) {
                            $replyFecha = date('Y-m-d H:i', $reply['date']['created']);
                        } else {
                            $replyFecha = date('Y-m-d H:i', $reply['date']);
                        }

                        $output .= "  * **$replyUsuario** ($replyFecha): " . trim($reply['raw']) . "\n";
                    }
                }
                $output .= "\n";
            }

            $output .= "----\n\n";
            $contador++;
        }

        $output .= "//Documento generado automáticamente por el sistema de Control Administrativo.//\n";

        return $output;
    }

    /**
     * Exporta comentarios a una nueva página wiki
     * @param string $paginaOrigen ej: 'encargos:general5'
     * @param string $paginaDestino ej: 'encargos:registros:general5_20260131'
     * @param int $aplicadorId
     * @param string $usuario username que realiza la exportación
     * @return array ['success' => bool, 'mensaje' => string, 'pagina' => string]
     */
    public function exportarComentarios($paginaOrigen, $paginaDestino, $aplicadorId = null, $usuario = '') {
        // Verificar que la página origen existe y tiene comentarios
        $data = $this->leerComentariosDiscussion($paginaOrigen);

        if (!$data) {
            return [
                'success' => false,
                'mensaje' => 'La página origen no tiene sección de discusión.',
                'pagina' => ''
            ];
        }

        $cantidadComentarios = intval($data['number']);

        if ($cantidadComentarios == 0) {
            return [
                'success' => false,
                'mensaje' => 'No hay comentarios para exportar.',
                'pagina' => ''
            ];
        }

        // Generar contenido
        $contenido = $this->extraerComentariosATexto($paginaOrigen);

        // Guardar la nueva página
        saveWikiText($paginaDestino, $contenido, "Exportación de registros desde $paginaOrigen", false);

        // Aprobar automáticamente la página creada
        $this->aprobarPagina($paginaDestino);

        // Registrar en log
        $queryLog = "INSERT INTO admin_control_export_log
                     (aplicador_id, pagina_origen, pagina_destino, comentarios_exportados, exportado_por)
                     VALUES (?, ?, ?, ?, ?)";
        $this->sqlite->query($queryLog, [$aplicadorId, $paginaOrigen, $paginaDestino, $cantidadComentarios, $usuario]);

        return [
            'success' => true,
            'mensaje' => "Se exportaron $cantidadComentarios registros exitosamente.",
            'pagina' => $paginaDestino
        ];
    }

    /**
     * Debug log para aprobar página
     */
    protected function debugLogApproval($message) {
        $logFile = DOKU_PLUGIN . 'autoapprove/debug.log';
        $timestamp = date('Y-m-d H:i:s');
        @file_put_contents($logFile, "[$timestamp] [BEZ-Control] $message\n", FILE_APPEND);
    }

    /**
     * Aprueba automáticamente una página recién creada
     * @param string $id ID de la página wiki
     */
    protected function aprobarPagina($id) {
        $this->debugLogApproval("aprobarPagina() called for: $id");

        // Cargar helper de publish
        $publishHelper = plugin_load('helper', 'publish');
        if (!$publishHelper) {
            $this->debugLogApproval("ERROR: publish helper not available");
            return; // Plugin publish no disponible
        }

        // Obtener la revisión actual de la página
        $file = wikiFN($id);
        $this->debugLogApproval("Wiki file path: $file");

        $revision = @filemtime($file);
        if (!$revision) {
            $revision = time();
            $this->debugLogApproval("No filemtime, using time(): $revision");
        } else {
            $this->debugLogApproval("Got revision from filemtime: $revision");
        }

        // Obtener aprobaciones existentes
        $meta = p_get_metadata($id);
        $approvals = isset($meta['approval']) ? $meta['approval'] : [];
        $this->debugLogApproval("Existing approvals: " . json_encode($approvals));

        // Crear entrada de aprobación
        if (!isset($approvals[$revision])) {
            $approvals[$revision] = [];
        }

        // Agregar aprobación del sistema
        $approvals[$revision]['bez_system'] = [
            'BEZ-System',            // client
            'system',                // user
            'system@bez',            // mail
            $revision                // timestamp
        ];

        $this->debugLogApproval("New approvals: " . json_encode($approvals));

        // Guardar metadata de aprobación
        $result = p_set_metadata($id, ['approval' => $approvals], true, true);
        $this->debugLogApproval("p_set_metadata result: " . var_export($result, true));

        // Verificar
        $checkMeta = p_get_metadata($id);
        $this->debugLogApproval("Verification: " . json_encode(isset($checkMeta['approval']) ? $checkMeta['approval'] : 'NOT SET'));
    }

    /**
     * Obtiene el historial de exportaciones
     * @param int $limite
     * @return array
     */
    public function getHistorialExportaciones($limite = 20) {
        $query = "SELECT e.*, a.nombre as aplicador_nombre
                  FROM admin_control_export_log e
                  LEFT JOIN admin_control_aplicadores a ON e.aplicador_id = a.id
                  ORDER BY e.exportado_at DESC
                  LIMIT ?";
        $res = $this->sqlite->query($query, [$limite]);
        return $this->sqlite->res2arr($res);
    }

    /**
     * Genera la lista de páginas disponibles para exportar (general1 a general20)
     * @param string $prefijo ej: 'encargos:general'
     * @param int $cantidad
     * @return array
     */
    public function generarListaPaginasExportar($prefijo = 'encargos:general', $cantidad = 20) {
        $paginas = [];

        // Página principal (sin número)
        $paginas[] = [
            'id' => $prefijo,
            'nombre' => 'general (principal)',
            'comentarios' => $this->contarComentarios($prefijo)
        ];

        // Páginas numeradas
        for ($i = 1; $i <= $cantidad; $i++) {
            $pageId = $prefijo . $i;
            $paginas[] = [
                'id' => $pageId,
                'nombre' => "general$i",
                'comentarios' => $this->contarComentarios($pageId)
            ];
        }

        return $paginas;
    }
}
