<?php

class Generarauto
{
    /**
     * Autoriza un comprobante ante el SRI.
     * @param string $xmlmues        Nombre de archivo firmado (p.ej. 123...49digitos.xml)
     * @param int    $delaySeconds   Segundos a esperar antes de llamar a Autorización (solo esta ejecución)
     */
    public function Autorizacionxml(string $xmlmues, int $delaySeconds = 0)
    {
        // === Espera SOLO para esta llamada (no afecta a otras "fichas") ===
        if ($delaySeconds > 0) {
            sleep($delaySeconds);
        }

        $respuestamen = [];

        // === Rutas ===
        $dirBase     = __DIR__;
        $dirFirmado  = $dirBase . '/../firmaecu/firmado';
        $dirAut      = $dirBase . '/autorizados';
        $dirNoAut    = $dirBase . '/no_autorizado';
        $dirResp     = $dirBase . '/respuestas';
        $dirPretty   = $dirBase . '/autorizaciones_xml';        // === EXTRA: carpeta “bonito”

        @mkdir($dirAut,   0775, true);
        @mkdir($dirNoAut, 0775, true);
        @mkdir($dirResp,  0775, true);
        @mkdir($dirPretty,0775, true);                          // === EXTRA

        // === Obtener claveAcceso desde el XML o desde el nombre de archivo ===
        $rutaFirmado = $dirFirmado . '/' . $xmlmues;
        $claveAcceso = null;

        if (is_file($rutaFirmado)) {
            $xmlContenido = @file_get_contents($rutaFirmado) ?: '';
            if ($xmlContenido && preg_match('/<claveAcceso>(\d{10,60})<\/claveAcceso>/', $xmlContenido, $m)) {
                $claveAcceso = $m[1]; // clave de acceso extraída del XML
            }
        }

        // Si no se encontró en el contenido, intentar desde el nombre del archivo (sin extensión)
        if (!$claveAcceso) {
            $base = pathinfo($xmlmues, PATHINFO_FILENAME);
            if (preg_match('/^\d{10,60}$/', $base)) {
                $claveAcceso = $base;
            }
        }

        if (!$claveAcceso) {
            // No podemos autorizar sin claveAcceso
            $respuestamen[] = "No se pudo determinar la claveAcceso (ni en el XML ni en el nombre de archivo).";
            $this->registrarRespuestaDB($respuestamen, "N/A");
            return;
        }

        // === Ambiente (pruebas o producción) ===
        $ambiente = "pruebas"; // Cambia a "produccion" cuando sea necesario
        $wsdl = ($ambiente === "pruebas")
            ? "https://celcer.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantesOffline?wsdl"
            : "https://cel.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantesOffline?wsdl";

        try {
            // Crear cliente SOAP
            $client = new SoapClient($wsdl, [
                "trace" => true,
                "cache_wsdl" => WSDL_CACHE_NONE,
                "connection_timeout" => 30,
                "stream_context" => stream_context_create([
                    'http' => ['timeout' => 30]
                ]),
            ]);

            // Enviar la clave de acceso al SRI (con reintentos si está en proceso)
            $parametros  = ["claveAccesoComprobante" => $claveAcceso];
            $maxIntentos = 3;   // ajustable
            $esperaSeg   = 3;   // ajustable

            $respuesta = null;
            for ($i = 1; $i <= $maxIntentos; $i++) {
                $respuesta = $client->autorizacionComprobante($parametros);

                // Guardar SIEMPRE la respuesta SOAP cruda (evidencia)
                $raw = (string)$client->__getLastResponse();
                file_put_contents($dirResp . '/' . $claveAcceso . "_resp_autorizacion_int{$i}.xml", $raw);

                $hayAut =
                    isset($respuesta->RespuestaAutorizacionComprobante) &&
                    isset($respuesta->RespuestaAutorizacionComprobante->autorizaciones) &&
                    isset($respuesta->RespuestaAutorizacionComprobante->autorizaciones->autorizacion);

                if ($hayAut) {
                    $aut = $respuesta->RespuestaAutorizacionComprobante->autorizaciones->autorizacion;
                    if (!is_array($aut)) $aut = [$aut];
                    $estadoPrimero = strtoupper(trim((string)($aut[0]->estado ?? '')));
                    if ($estadoPrimero === 'PPR' || $estadoPrimero === 'EN PROCESO' || $estadoPrimero === 'PROCESO') {
                        sleep($esperaSeg);
                        continue; // reintenta
                    }
                    break; // ya hay estado definitivo (AUT/NAT)
                } else {
                    sleep($esperaSeg);
                }
            }

            $respuestamen[] = "Respuesta de Autorización del SRI:";

            if (
                isset($respuesta->RespuestaAutorizacionComprobante) &&
                isset($respuesta->RespuestaAutorizacionComprobante->autorizaciones) &&
                isset($respuesta->RespuestaAutorizacionComprobante->autorizaciones->autorizacion)
            ) {
                $autorizaciones = $respuesta->RespuestaAutorizacionComprobante->autorizaciones->autorizacion;
                if (!is_array($autorizaciones)) $autorizaciones = [$autorizaciones];

                foreach ($autorizaciones as $aut) {
                    $estado = strtoupper(trim((string)($aut->estado ?? 'N/D')));
                    $fecha  = (string)($aut->fechaAutorizacion ?? 'N/D');
                    $numAut = (string)($aut->numeroAutorizacion ?? 'N/D');
                    $ambWss = (string)($aut->ambiente ?? 'N/D');

                    $respuestamen[] = "Estado: $estado";
                    $respuestamen[] = "Fecha de Autorización: $fecha";
                    $respuestamen[] = "Número de Autorización: $numAut";
                    $respuestamen[] = "Ambiente: $ambWss";

                    // --- Manejo del <comprobante> (puede venir CDATA, escapado o no venir) ---
                    $comprobantePlano = null;
                    if (isset($aut->comprobante)) {
                        $comprobantePlano = $this->normalizarComprobante((string)$aut->comprobante);
                    }

                    // === Guarda como antes (no tocamos tu flujo) ===
                    if ($estado === 'AUTORIZADO') {
                        if ($comprobantePlano !== null && $comprobantePlano !== '') {
                            $rutaComprobante = $dirAut . '/' . $claveAcceso . '.xml';
                            file_put_contents($rutaComprobante, $comprobantePlano);
                            $respuestamen[] = "XML autorizado guardado: $rutaComprobante";
                        }
                    } else { // NO AUTORIZADO u otro
                        if ($comprobantePlano !== null && $comprobantePlano !== '') {
                            $rutaNoAut = $dirNoAut . '/' . $claveAcceso . '_comprobante.xml';
                            file_put_contents($rutaNoAut, $comprobantePlano);
                            $respuestamen[] = "XML NO AUTORIZADO (comprobante) guardado: $rutaNoAut";
                        } else {
                            // No vino <comprobante>: copia el firmado original para trazabilidad
                            if (is_file($rutaFirmado)) {
                                $rutaCopiaFirmado = $dirNoAut . '/' . $claveAcceso . '_firmado.xml';
                                @copy($rutaFirmado, $rutaCopiaFirmado);
                                $respuestamen[] = "No vino <comprobante>. Copiado el firmado a: $rutaCopiaFirmado";
                            } else {
                                $respuestamen[] = "No vino <comprobante> y no se encontró el firmado para copiar.";
                            }
                        }
                    }

                    // --- Mensajes de error / info ---
                    $mensajes = null;
                    if (isset($aut->mensajes)) {
                        $mensajes = $aut->mensajes->mensaje;
                        if (!is_array($mensajes)) $mensajes = [$mensajes];
                        foreach ($mensajes as $msg) {
                            $id   = (string)($msg->identificador ?? '');
                            $tit  = (string)($msg->mensaje ?? '');
                            $tipo = (string)($msg->tipo ?? '');
                            $inf  = (string)($msg->informacionAdicional ?? '');
                            $respuestamen[] = "[$tipo $id] $tit";
                            if ($inf !== '') {
                                $respuestamen[] = "Detalle: $inf";
                            }
                        }
                    }

                    // === EXTRA: Generar el XML “bonito” de <autorizacion> con CDATA ===
                    $xmlPretty = $this->construirAutorizacionBonita(
                        $estado,
                        $numAut,
                        $fecha,
                        $ambWss,
                        $comprobantePlano,
                        $mensajes
                    );

                    if ($xmlPretty) {
                        $nombrePretty =
                            ($estado === 'AUTORIZADO')
                                ? $dirPretty . '/' . $claveAcceso . '_autorizacion.xml'
                                : $dirPretty . '/' . $claveAcceso . '_no_autorizado.xml';

                        file_put_contents($nombrePretty, $xmlPretty);
                        $respuestamen[] = "Autorización guardada: $nombrePretty";
                    }
                }
            } else {
                $respuestamen[] = "No se encontraron autorizaciones (posible PPR). Revisa /respuestas/ y reintenta.";
            }

        } catch (SoapFault $e) {
            $respuestamen[] = "Error SOAP:";
            $respuestamen[] = "Código: " . $e->faultcode;
            $respuestamen[] = "Mensaje: " . $e->faultstring;
        }

        // === Registrar en BD (igual que tu versión) ===
        $this->registrarRespuestaDB($respuestamen, $claveAcceso);
    }

    /**
     * Normaliza el contenido del nodo <comprobante> devolviéndolo como XML real.
     * - Extrae CDATA si existe
     * - Decodifica &lt; &gt; &amp; si viene escapado
     * - Intenta formatear con DOM (opcional)
     */
    private function normalizarComprobante(string $raw): string
    {
        $comp = trim($raw);

        // 1) Extraer CDATA si corresponde
        if (strpos($comp, '<![CDATA[') !== false) {
            $comp = preg_replace('/^<!\[CDATA\[(.*)\]\]>$/s', '$1', $comp);
            $comp = trim($comp);
        }

        // 2) Decodificar entidades si viene escapado (&lt; &gt; &amp; &quot; ...)
        if (strpos($comp, '&lt;') !== false ||
            strpos($comp, '&gt;') !== false ||
            strpos($comp, '&amp;') !== false ||
            strpos($comp, '&quot;') !== false ||
            strpos($comp, '&#039;') !== false) {
            $comp = html_entity_decode($comp, ENT_QUOTES | ENT_XML1, 'UTF-8');
        }

        // 3) Validar / embellecer (si es XML válido)
        $doc = new DOMDocument('1.0', 'UTF-8');
        $doc->preserveWhiteSpace = false;
        $doc->formatOutput = true;
        if (@$doc->loadXML($comp)) {
            $comp = $doc->saveXML();
        }

        return $comp;
    }

    // =============================== EXTRA: helpers “bonito” ===============================

    /**
     * Construye el XML de <autorizacion> “bonito” con <comprobante> en CDATA.
     * Acepta cualquier estado (AUTORIZADO, NO AUTORIZADO, etc.).
     * $mensajes puede ser array de objetos/arrays SRI o null.
     */
    private function construirAutorizacionBonita(
        string $estado,
        string $numeroAutorizacion,
        string $fechaAutorizacion,
        string $ambiente,
        ?string $comprobantePlano,
        $mensajes
    ): ?string {
        // Asegurar CDATA del comprobante (si existe)
        $comprobanteCDATA = '';
        if ($comprobantePlano !== null && $comprobantePlano !== '') {
            $comprobanteCDATA = $this->toCDATA($comprobantePlano);
        }

        // Construir <mensajes> si existen
        $mensajesXml = '<mensajes/>';
        if (is_array($mensajes) && count($mensajes) > 0) {
            $items = [];
            foreach ($mensajes as $m) {
                // Soporta objeto stdClass o array
                $id   = htmlspecialchars((string)($m->identificador ?? ($m['identificador'] ?? '')), ENT_XML1 | ENT_COMPAT, 'UTF-8');
                $tip  = htmlspecialchars((string)($m->tipo ?? ($m['tipo'] ?? '')), ENT_XML1 | ENT_COMPAT, 'UTF-8');
                $men  = htmlspecialchars((string)($m->mensaje ?? ($m['mensaje'] ?? '')), ENT_XML1 | ENT_COMPAT, 'UTF-8');
                $inf  = htmlspecialchars((string)($m->informacionAdicional ?? ($m['informacionAdicional'] ?? '')), ENT_XML1 | ENT_COMPAT, 'UTF-8');

                $items[] =
                    "<mensaje>" .
                        ($id !== ''  ? "<identificador>{$id}</identificador>" : "") .
                        ($tip !== '' ? "<tipo>{$tip}</tipo>" : "") .
                        ($men !== '' ? "<mensaje>{$men}</mensaje>" : "") .
                        ($inf !== '' ? "<informacionAdicional>{$inf}</informacionAdicional>" : "") .
                    "</mensaje>";
            }
            $mensajesXml = "<mensajes>" . implode('', $items) . "</mensajes>";
        }

        // Armar el documento final
        $estadoEsc = htmlspecialchars($estado, ENT_XML1 | ENT_COMPAT, 'UTF-8');
        $numEsc    = htmlspecialchars($numeroAutorizacion, ENT_XML1 | ENT_COMPAT, 'UTF-8');
        $fecEsc    = htmlspecialchars($fechaAutorizacion, ENT_XML1 | ENT_COMPAT, 'UTF-8');
        $ambEsc    = htmlspecialchars($ambiente, ENT_XML1 | ENT_COMPAT, 'UTF-8');

        $xml =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
            "<autorizacion>\n" .
            "  <estado>{$estadoEsc}</estado>\n" .
            "  <numeroAutorizacion>{$numEsc}</numeroAutorizacion>\n" .
            "  <fechaAutorizacion>{$fecEsc}</fechaAutorizacion>\n" .
            "  <ambiente>{$ambEsc}</ambiente>\n" .
            "  <comprobante>{$comprobanteCDATA}</comprobante>\n" .
            "  {$mensajesXml}\n" .
            "</autorizacion>\n";

        // Validación ligera
        $doc = new DOMDocument('1.0', 'UTF-8');
        $doc->preserveWhiteSpace = false;
        $doc->formatOutput = true;
        if (@$doc->loadXML($xml)) {
            return $doc->saveXML();
        }
        return $xml; // En el improbable caso que no cargue, devolvemos igual.
    }

    /**
     * Envuelve texto en CDATA, dividiendo “]]>” si llega a existir dentro.
     */
    private function toCDATA(string $text): string
    {
        // Normalizar saltos y quitar BOM potencial
        $text = preg_replace('/^\xEF\xBB\xBF/', '', $text);
        // Evitar romper CDATA si el contenido trae "]]>"
        $text = str_replace("]]>", "]]]]><![CDATA[>", $text);
        return "<![CDATA[" . $text . "]]>";
    }

    // ============================ /EXTRA: helpers “bonito” ============================

    /**
     * Inserta la respuesta en la tabla respuestadoc
     * (MISMA firma y estructura que usabas)
     */
    private function registrarRespuestaDB(array $respuestamen, string $documento)
    {
        include 'conexion1.php';
        $cn = new mysqli($servidor, $nombre, $clave, $base);
        if ($cn->connect_errno) {
            // Si falla la conexión, evita romper la ejecución
            return;
        }
        $cn->set_charset("utf8mb4");

        $dato1 = $documento; // almacenamos la claveAcceso consultada
        $dato2 = "0";
        $respuestax = implode(" ", $respuestamen);
        $fecha = date('Y-m-d');
        $hora  = date('H:i:s');

        $sql = "INSERT INTO respuestaauto 
                (FECHAREGISTRO, HORAREGISTRO, DOCUMENTO, DATO1, DATO2, RESPUESTA)
                VALUES (?,?,?,?,?,?)";
        $stmt = $cn->prepare($sql);
        if ($stmt) {
            $stmt->bind_param('ssssss', $fecha, $hora, $documento, $dato1, $dato2, $respuestax);
            $stmt->execute();
            $stmt->close();
        }
    }
}
