<?php
/**
 * API: Extracción de texto de archivos de contrato
 * Acepta: .txt, .pdf (básico), .docx, .doc
 * Devuelve: { success: bool, html: string, message?: string }
 */
require_once __DIR__ . '/../../../config/bootstrap.php';


header('Content-Type: application/json');


if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Método no permitido']);
    exit;
}

if (empty($_FILES['archivo']) || $_FILES['archivo']['error'] !== UPLOAD_ERR_OK) {
    $uploadErrors = [
        UPLOAD_ERR_INI_SIZE   => 'El archivo supera el límite del servidor.',
        UPLOAD_ERR_FORM_SIZE  => 'El archivo supera el límite del formulario.',
        UPLOAD_ERR_PARTIAL    => 'El archivo se subió parcialmente.',
        UPLOAD_ERR_NO_FILE    => 'No se seleccionó ningún archivo.',
        UPLOAD_ERR_NO_TMP_DIR => 'Directorio temporal no encontrado.',
        UPLOAD_ERR_CANT_WRITE => 'No se pudo escribir el archivo.',
    ];
    $code = $_FILES['archivo']['error'] ?? UPLOAD_ERR_NO_FILE;
    echo json_encode([
        'success' => false,
        'message' => $uploadErrors[$code] ?? 'Error desconocido al subir el archivo.'
    ]);
    exit;
}

$file     = $_FILES['archivo'];
$tmpPath  = $file['tmp_name'];
$origName = $file['name'];
$ext      = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
$maxSize  = 10 * 1024 * 1024; // 10 MB

// Validar tamaño
if ($file['size'] > $maxSize) {
    echo json_encode(['success' => false, 'message' => 'El archivo no debe superar 10 MB.']);
    exit;
}

// Validar extensión permitida
$allowed = ['txt', 'pdf', 'docx', 'doc', 'rtf'];
if (!in_array($ext, $allowed)) {
    echo json_encode(['success' => false, 'message' => 'Formato no soportado. Use: TXT, PDF, DOCX, DOC o RTF.']);
    exit;
}

// Validar MIME real
$finfo    = finfo_open(FILEINFO_MIME_TYPE);
$mimeReal = finfo_file($finfo, $tmpPath);
finfo_close($finfo);

$allowedMimes = [
    'text/plain',
    'application/pdf',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/msword',
    'application/rtf',
    'text/rtf',
    'application/zip', // DOCX es zip internamente
    'application/octet-stream',
];

if (!in_array($mimeReal, $allowedMimes)) {
    echo json_encode(['success' => false, 'message' => 'El archivo no es del tipo esperado.']);
    exit;
}

try {
    $html = '';

    switch ($ext) {
        case 'txt':
            $html = extractFromTxt($tmpPath);
            break;

        case 'rtf':
            $html = extractFromRtf($tmpPath);
            break;

        case 'docx':
            $html = extractFromDocx($tmpPath);
            break;

        case 'doc':
            $html = extractFromDoc($tmpPath);
            break;

        case 'pdf':
            $html = extractFromPdf($tmpPath);
            break;

        default:
            throw new \Exception('Formato no soportado.');
    }

    if (empty(trim(strip_tags($html)))) {
        echo json_encode([
            'success' => false,
            'message' => 'No se pudo extraer texto del archivo. Verifica que no esté vacío o sea solo imágenes.'
        ]);
        exit;
    }

    echo json_encode(['success' => true, 'html' => $html]);
} catch (\Exception $e) {
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

// ============================================================================
// EXTRACTORES
// ============================================================================

function extractFromTxt(string $path): string
{
    $raw = file_get_contents($path);

    // Detectar y convertir encoding
    $encoding = mb_detect_encoding($raw, ['UTF-8', 'ISO-8859-1', 'Windows-1252'], true);
    if ($encoding && $encoding !== 'UTF-8') {
        $raw = mb_convert_encoding($raw, 'UTF-8', $encoding);
    }

    // Convertir a HTML preservando estructura básica
    $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $raw));
    $html  = '';
    $inList = false;

    foreach ($lines as $line) {
        $line = htmlspecialchars(rtrim($line));

        if ($line === '') {
            if ($inList) { $html .= '</ul>'; $inList = false; }
            $html .= '<p><br></p>';
            continue;
        }

        // Detectar items de lista (guión o asterisco al inicio)
        if (preg_match('/^[-*•]\s+(.+)/', $line, $m)) {
            if (!$inList) { $html .= '<ul>'; $inList = true; }
            $html .= '<li>' . $m[1] . '</li>';
            continue;
        }

        // Detectar listas numeradas
        if (preg_match('/^\d+[.)]\s+(.+)/', $line, $m)) {
            if (!$inList) { $html .= '<ol>'; $inList = true; }
            $html .= '<li>' . $m[1] . '</li>';
            continue;
        }

        if ($inList) { $html .= '</ul>'; $inList = false; }

        // Líneas en mayúsculas totales → encabezado
        if (mb_strtoupper($line) === $line && mb_strlen($line) > 5 && mb_strlen($line) < 100) {
            $html .= '<h2>' . $line . '</h2>';
        } else {
            $html .= '<p>' . $line . '</p>';
        }
    }

    if ($inList) $html .= '</ul>';

    return $html;
}

function extractFromRtf(string $path): string
{
    $raw = file_get_contents($path);

    // Remover grupos RTF y comandos
    $text = preg_replace('/\{\\\\[^{}]*\}/', '', $raw);
    $text = preg_replace('/\\\\[a-z]+\d*\s?/', ' ', $text);
    $text = preg_replace('/[{}\\\\]/', '', $text);
    $text = html_entity_decode($text);
    $text = trim($text);

    // Pasar por extractor de texto plano
    file_put_contents($path . '.txt', $text);
    $html = extractFromTxt($path . '.txt');
    @unlink($path . '.txt');

    return $html;
}

function extractFromDocx(string $path): string
{
    if (!class_exists('ZipArchive')) {
        throw new \Exception('El servidor no soporta lectura de archivos DOCX (ZipArchive no disponible).');
    }

    $zip = new ZipArchive();
    if ($zip->open($path) !== true) {
        throw new \Exception('No se pudo abrir el archivo DOCX.');
    }

    // Leer word/document.xml
    $xmlContent = $zip->getFromName('word/document.xml');
    $zip->close();

    if ($xmlContent === false) {
        throw new \Exception('El archivo DOCX no contiene contenido de documento válido.');
    }

    return docxXmlToHtml($xmlContent);
}

function docxXmlToHtml(string $xml): string
{
    libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $dom->loadXML($xml);

    $html   = '';
    $body   = $dom->getElementsByTagNameNS('*', 'body')->item(0);

    if (!$body) {
        // Fallback: strip tags
        $text = strip_tags(str_replace(['</w:p>', '</w:tr>'], "\n", $xml));
        return extractFromTxt(tempnamWrite($text));
    }

    foreach ($body->childNodes as $node) {
        $localName = $node->localName;

        if ($localName === 'p') {
            // Detectar si es encabezado
            $style = '';
            $pPr   = getChildByLocalName($node, 'pPr');
            if ($pPr) {
                $pStyle = getChildByLocalName($pPr, 'pStyle');
                if ($pStyle) $style = $pStyle->getAttribute('w:val');
            }

            $text = extractTextFromParagraph($node);

            if ($text === '') {
                $html .= '<p><br></p>';
                continue;
            }

            if (preg_match('/^Heading(\d)/i', $style, $m)) {
                $level = min((int)$m[1], 3);
                $html .= "<h{$level}>" . htmlspecialchars($text) . "</h{$level}>";
            } elseif (stripos($style, 'Title') !== false) {
                $html .= '<h1>' . htmlspecialchars($text) . '</h1>';
            } else {
                $html .= '<p>' . htmlspecialchars($text) . '</p>';
            }
        } elseif ($localName === 'tbl') {
            // Tablas: extraer solo texto
            foreach ($node->getElementsByTagNameNS('*', 'tr') as $tr) {
                $cells = [];
                foreach ($tr->getElementsByTagNameNS('*', 'tc') as $tc) {
                    $cells[] = htmlspecialchars(extractTextFromParagraph($tc));
                }
                $html .= '<p>' . implode(' | ', $cells) . '</p>';
            }
        }
    }

    return $html ?: '<p>El documento se procesó pero no tiene contenido de texto.</p>';
}

function extractTextFromParagraph(DOMNode $node): string
{
    $text = '';
    foreach ($node->getElementsByTagNameNS('*', 't') as $t) {
        $text .= $t->textContent;
    }
    return trim($text);
}

function getChildByLocalName(DOMNode $parent, string $localName): ?DOMNode
{
    foreach ($parent->childNodes as $child) {
        if ($child->localName === $localName) return $child;
    }
    return null;
}

function tempnamWrite(string $text): string
{
    $tmp = tempnam(sys_get_temp_dir(), 'contract_');
    file_put_contents($tmp, $text);
    return $tmp;
}

function extractFromDoc(string $path): string
{
    // DOC binario: extraer texto legible con regex básico
    $raw  = file_get_contents($path);
    // Extraer secuencias de caracteres imprimibles de más de 4 chars
    preg_match_all('/[\x20-\x7E\xC0-\xFF]{4,}/', $raw, $matches);
    $text = implode(' ', $matches[0]);
    $text = preg_replace('/\s{2,}/', "\n", $text);

    $tmp = tempnam(sys_get_temp_dir(), 'doc_');
    file_put_contents($tmp, $text);
    $html = extractFromTxt($tmp);
    @unlink($tmp);

    return $html;
}

function extractFromPdf(string $path): string
{
    // Intentar con pdftotext si está disponible en el sistema
    $escaped = escapeshellarg($path);
    $output  = shell_exec("pdftotext -enc UTF-8 -layout {$escaped} - 2>/dev/null");

    if (!empty($output)) {
        $tmp = tempnam(sys_get_temp_dir(), 'pdf_');
        file_put_contents($tmp, $output);
        $html = extractFromTxt($tmp);
        @unlink($tmp);
        return $html;
    }

    // Fallback: extracción básica de texto de PDF sin herramienta externa
    $raw   = file_get_contents($path);
    $texts = [];

    // Extraer streams de texto entre BT y ET
    preg_match_all('/BT(.+?)ET/s', $raw, $streams);
    foreach ($streams[1] as $stream) {
        // Extraer cadenas entre paréntesis y corchetes
        preg_match_all('/\(([^)]*)\)|<([0-9a-fA-F]+)>/', $stream, $strings);
        foreach ($strings[1] as $s) {
            $decoded = @preg_replace('/\\\\([nrtbf\\\\\(\)])/', ' ', $s);
            if (!empty(trim($decoded))) $texts[] = trim($decoded);
        }
        // Hex strings
        foreach ($strings[2] as $hex) {
            $bytes = '';
            for ($i = 0; $i < strlen($hex); $i += 2) {
                $bytes .= chr(hexdec(substr($hex, $i, 2)));
            }
            $decoded = mb_convert_encoding($bytes, 'UTF-8', 'UTF-16BE');
            if (!empty(trim($decoded))) $texts[] = trim($decoded);
        }
    }

    if (empty($texts)) {
        throw new \Exception(
            'No se pudo extraer texto del PDF. ' .
            'Si es un PDF escaneado (solo imágenes), copia el texto manualmente en el editor.'
        );
    }

    $text = implode(' ', $texts);
    $tmp  = tempnam(sys_get_temp_dir(), 'pdf_');
    file_put_contents($tmp, $text);
    $html = extractFromTxt($tmp);
    @unlink($tmp);

    return $html;
}
