<?php

namespace App\Console\Commands;

use App\Models\RequestDescargaProgramada;
use App\Models\FacturaExterna;
use App\Models\Proveedor;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use SimpleXMLElement;

class ProcessPendingXmls extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:process-pending-xmls {--limit=5}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Procesar XMLs descargados pendientes y guardarlos en FacturaExterna';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $limit = $this->option('limit');
        
        $this->info("Iniciando procesamiento de XMLs pendientes (límite: {$limit})");
        
        // Buscar solicitudes en estado 'por_procesar'
        $solicitudes = RequestDescargaProgramada::where('status', 'por_procesar')
            ->with('proveedor')
            ->orderBy('created_at', 'asc')
            ->limit($limit)
            ->get();
            
        $this->info("Se encontraron {$solicitudes->count()} solicitudes para procesar");
        
        $processed = 0;
        $errors = 0;
        
        foreach ($solicitudes as $solicitud) {
            try {
                $this->line("Procesando solicitud ID: {$solicitud->id} - RFC: {$solicitud->proveedor->rFCEmisor}");
                
                $result = $this->processSolicitud($solicitud);
                
                if ($result) {
                    $processed++;
                    $this->info("✓ Solicitud {$solicitud->id} procesada exitosamente");
                } else {
                    $this->line("⏳ No se encontraron XMLs para procesar en solicitud {$solicitud->id}");
                }
            } catch (\Exception $e) {
                $errors++;
                $this->error("✗ Error procesando solicitud {$solicitud->id}: " . $e->getMessage());
                Log::error('Procesamiento XMLs: Error procesando solicitud', [
                    'solicitud_id' => $solicitud->id,
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);
            }
        }
        
        $this->info("Procesamiento completado. Éxitos: {$processed}, Errores: {$errors}");
        
        return Command::SUCCESS;
    }
    
    /**
     * Procesar una solicitud individual
     */
    private function processSolicitud(RequestDescargaProgramada $solicitud): bool
    {
        $proveedor = $solicitud->proveedor;
        $rfc = strtoupper($proveedor->rFCEmisor);
        
        // Rutas configurables
        $sourceFolder = config('sat.xml_storage_path') . '/' . $rfc;
        $destFolder = config('sat.processed_xml_path', storage_path('app/processed_xmls'));
        
        $this->line("  → Carpeta fuente: {$sourceFolder}");
        $this->line("  → Carpeta destino: {$destFolder}");
        
        // Asegurar que la carpeta destino exista
        if (!is_dir($destFolder)) {
            mkdir($destFolder, 0755, true);
        }
        
        // Verificar que la carpeta fuente exista
        if (!is_dir($sourceFolder)) {
            $this->error("La carpeta fuente no existe: {$sourceFolder}");
            return false;
        }
        
        // Obtener facturas existentes para evitar duplicados
        $existingUuids = FacturaExterna::where('id_proveedor', $proveedor->id_proveedor)
            ->where('status', 1)
            ->pluck('UUID')
            ->toArray();
        
        $files = scandir($sourceFolder);
        $processedCount = 0;
        $sqlInserts = [];
        
        libxml_use_internal_errors(true);
        
        foreach ($files as $xmlFile) {
            if (in_array($xmlFile, ['.', '..'])) {
                continue;
            }
            
            $filePath = $sourceFolder . '/' . $xmlFile;
            
            // Omitir archivos muy pequeños (probablemente corruptos)
            if (filesize($filePath) < 1500) {
                unlink($filePath);
                continue;
            }
            
            // Cargar XML
            $xmlObj = simplexml_load_file(
                $filePath,
                'SimpleXMLElement',
                LIBXML_NOCDATA | LIBXML_NSCLEAN | LIBXML_NOERROR | LIBXML_NOWARNING
            );
            
            if ($xmlObj === false) {
                unlink($filePath);
                continue;
            }
            
            // Obtener namespaces
            $ns = $xmlObj->getNamespaces(true);
            $xmlObj->registerXPathNamespace('cfdi', $ns['cfdi']);
            $xmlObj->registerXPathNamespace('tfd', $ns['tfd']);
            
            // Obtener UUID del TimbreFiscalDigital
            $tfdNode = $xmlObj->xpath('//tfd:TimbreFiscalDigital')[0] ?? null;
            $uuid = (string) $tfdNode['UUID'] ?? null;
            
            if (!$uuid) {
                unlink($filePath);
                continue;
            }
            
            // Verificar que no exista previamente
            if (in_array($uuid, $existingUuids)) {
                unlink($filePath);
                continue;
            }
            
            // Obtener datos del emisor y receptor
            $receptor = $xmlObj->xpath('//cfdi:Receptor')[0];
            $emisor = $xmlObj->xpath('//cfdi:Emisor')[0];
            
            if (!$receptor || !$emisor) {
                unlink($filePath);
                continue;
            }
            
            // Determinar versión del CFDI
            $version = (string) $xmlObj['Version'] ?: (string) $xmlObj['version'];
            
            // Tags según versión
            if (in_array($version, ['3.3', '4.0'])) {
                $rfcTag = 'Rfc';
                $fechaTag = 'Fecha';
                $folioTag = 'Folio';
                $tipoTag = 'TipoDeComprobante';
                $totalTag = 'Total';
                $subTotalTag = 'SubTotal';
            } else {
                $rfcTag = 'rfc';
                $fechaTag = 'fecha';
                $folioTag = 'folio';
                $tipoTag = 'tipoDeComprobante';
                $totalTag = 'total';
                $subTotalTag = 'subTotal';
            }
            
            $rfcRec = strtoupper((string) $receptor[$rfcTag]);
            $rfcEm = strtoupper((string) $emisor[$rfcTag]);
            
            // Validar que el RFC corresponda al proveedor
            if ($rfcRec !== $rfc && $rfcEm !== $rfc) {
                unlink($filePath);
                continue;
            }
            
            // Determinar tipo de documento (0=egreso, 1=ingreso)
            $tipoDocumento = ($rfcRec === $rfc) ? 0 : 1;
            
            // Si es nómina, invertir el tipo
            if (isset($ns['nomina12'])) {
                $tipoDocumento = $tipoDocumento ? 0 : 1;
            }
            
            // Extraer datos del CFDI
            $fechaTimbrado = (string) $tfdNode['FechaTimbrado'];
            $fechaAplicacion = (string) $xmlObj[$fechaTag];
            $folio = (string) $xmlObj[$folioTag];
            $tipoComp = (string) $xmlObj[$tipoTag];
            $total = (float) $xmlObj[$totalTag];
            $subTotal = (float) $xmlObj[$subTotalTag];
            
            // Preparar datos para inserción
            $sqlInserts[] = [
                'UUID' => $uuid,
                'id_proveedor' => $proveedor->id_proveedor,
                'RFCEmisor' => $rfcEm,
                'nombreEmisor' => (string) $emisor['Nombre'] ?? null,
                'RFCReceptor' => $rfcRec,
                'nombreReceptor' => (string) $receptor['Nombre'] ?? null,
                'fecha' => $fechaAplicacion,
                'fechaAplicacion' => date('Y-m-d', strtotime($fechaAplicacion)),
                'subTotal' => $subTotal,
                'total' => $total,
                'folio' => $folio,
                'tipo' => $tipoComp,
                'fechaCarga' => now(),
                'tipoDeComprobante' => $tipoComp,
                'fechaTimbrado' => $fechaTimbrado,
                'xmlFile' => $xmlFile,
                'tipoDocumento' => $tipoDocumento,
                'validacion' => 0,
                'statusDocumento' => 1,
                'status' => 1,
                'noCertificado' => (string) $xmlObj['NoCertificado'] ?? null,
                'noCertificadoSat' => (string) $tfdNode['NoCertificadoSAT'] ?? null,
                'moneda' => (string) $xmlObj['Moneda'] ?? null,
                'metodoPago' => (string) $xmlObj['MetodoPago'] ?? null,
                'totalImpuestosTrasladados' => null, // Se podría extraer si es necesario
                'totalImpuestosRetenidos' => null, // Se podría extraer si es necesario
                'isGastoPersonal' => 0,
            ];
            
            // Mover archivo a carpeta destino
            rename($filePath, $destFolder . '/' . $xmlFile);
            $processedCount++;
        }
        
        // Insertar facturas en lote
        if (!empty($sqlInserts)) {
            DB::table('FacturaExterna')->insert($sqlInserts);
        }
        
        // Si se procesó al menos un archivo, actualizar la solicitud
        if ($processedCount > 0) {
            $solicitud->update([
                'status' => 'procesado',
                'fecha_completado' => now(),
            ]);
            
            Log::info('Procesamiento XMLs: Solicitud actualizada', [
                'solicitud_id' => $solicitud->id,
                'archivos_procesados' => $processedCount,
                'status' => 'procesado',
            ]);
            
            return true;
        }
        
        // Si no hay archivos para procesar, igual marcar como procesado
        $solicitud->update([
            'status' => 'procesado',
            'fecha_completado' => now(),
        ]);
        
        return false;
    }
}
