<?php

namespace App\Http\Controllers;

use App\Models\ConfigImpresion;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Http;

class ConfigImpresionController extends Controller
{
    /**
     * Obtener todas las configuraciones de impresión
     */
    public function index(Request $request): JsonResponse
    {
        $tipoImpresion = $request->get('tipo_impresion');
        $sucursalId = $request->get('sucursal_id');
        
        $query = ConfigImpresion::with(['sucursal', 'user', 'sucursales', 'users']);
        
        // Si se especifica un tipo de impresión, filtrar por él
        if ($tipoImpresion) {
            $query->where('tipo_impresion', $tipoImpresion);
        }
        
        // Si se especifica una sucursal, filtrar por ella (usando relación many-to-many)
        if ($sucursalId) {
            $query->whereHas('sucursales', function($q) use ($sucursalId) {
                $q->where('sucursales.id', $sucursalId);
            });
        }
        
        $configuraciones = $query->orderBy('es_predeterminada', 'desc')
            ->orderBy('es_activa', 'desc')
            ->orderBy('nombre')
            ->get();

        return response()->json([
            'success' => true,
            'data' => $configuraciones
        ]);
    }

    /**
     * Obtener una configuración específica
     */
    public function show($id): JsonResponse
    {
        $configuracion = ConfigImpresion::with(['sucursal', 'user', 'sucursales', 'users'])->find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        return response()->json([
            'success' => true,
            'data' => $configuracion
        ]);
    }

    /**
     * Obtener la configuración activa por tipo
     */
    public function getActiva(Request $request): JsonResponse
    {
        $tipoImpresion = $request->get('tipo_impresion', 'ticket');
        $sucursalId = $request->get('sucursal_id');
        
        $configuracion = ConfigImpresion::getConfigActiva($tipoImpresion, $sucursalId);

        if (!$configuracion) {
            // Si no hay configuración activa, usar la predeterminada
            $configuracion = ConfigImpresion::getConfigPredeterminada($tipoImpresion, $sucursalId);
        }

        // Cargar relaciones
        if ($configuracion) {
            $configuracion->load(['sucursales', 'users']);
        }

        return response()->json([
            'success' => true,
            'data' => $configuracion
        ]);
    }

    /**
     * Crear una nueva configuración
     */
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'sucursales' => 'nullable|array',
            'sucursales.*' => 'integer|exists:sucursales,id',
            'users' => 'nullable|array',
            'users.*' => 'integer|exists:users,id',
            'nombre' => 'required|string|max:100',
            'tipo_impresion' => 'required|in:ticket,vale,datos_compra,etiquetas,otros',
            'ancho_papel' => 'required|integer|min:50|max:200',
            'alto_papel' => 'integer|min:0|max:500',
            'margen_superior' => 'numeric|min:0|max:50',
            'margen_inferior' => 'numeric|min:0|max:50',
            'margen_izquierdo' => 'numeric|min:0|max:50',
            'margen_derecho' => 'numeric|min:0|max:50',
            'fuente_principal' => 'required|string|max:50',
            'tamano_fuente_principal' => 'required|integer|min:8|max:72',
            'tamano_fuente_titulo' => 'required|integer|min:8|max:72',
            'tamano_fuente_subtitulo' => 'required|integer|min:8|max:72',
            'tamano_fuente_detalle' => 'required|integer|min:8|max:72',
            'color_texto' => 'required|string|regex:/^#[0-9A-Fa-f]{6}$/',
            'peso_fuente' => 'required|in:normal,bold,lighter,bolder',
            'interlineado' => 'required|numeric|min:0|max:3.0',
            'alineacion_titulo' => 'required|in:left,center,right',
            'alineacion_texto' => 'required|in:left,center,right',
            'alineacion_empresa' => 'required|in:left,center,right',
            'alineacion_direccion' => 'required|in:left,center,right',
            'alineacion_folio_fecha' => 'required|in:left,center,right',
            'alineacion_total' => 'required|in:left,center,right',
            'alineacion_footer' => 'required|in:left,center,right',
            'mostrar_logo' => 'boolean',
            'mostrar_fecha' => 'boolean',
            'mostrar_hora' => 'boolean',
            'mostrar_cliente' => 'boolean',
            'mostrar_empleado' => 'boolean',
            'mostrar_observaciones' => 'boolean',
            'separador_lineas' => 'string|max:10',
            'padding_celda' => 'numeric|min:0|max:20',
            'ancho_tabla' => 'integer|min:50|max:100',
            'ancho_contenido_porcentaje' => 'integer|min:50|max:100',
            'ancho_cuerpo_porcentaje' => 'integer|min:50|max:100',
            'es_activa' => 'boolean',
            'es_predeterminada' => 'boolean',
            'es_impresion_directa' => 'boolean',
            'ip_impresora' => 'required_if:es_impresion_directa,true|nullable|string|max:255',
            'ngrok_key' => 'required_if:es_impresion_directa,true|nullable|string|max:255',
        ]);

        // Validar usuarios si es impresión directa
        if ($request->es_impresion_directa) {
            $request->validate([
                'users' => 'required|array|min:1',
                'users.*' => 'integer|exists:users,id'
            ]);
        }

        $data = $request->all();
        $sucursales = $data['sucursales'] ?? [];
        $users = $data['users'] ?? [];
        
        // Remover arrays de datos antes de crear
        unset($data['sucursales'], $data['users']);

        $configuracion = ConfigImpresion::create($data);

        // Sincronizar sucursales
        if (!empty($sucursales)) {
            $configuracion->sucursales()->sync($sucursales);
        }

        // Sincronizar usuarios
        if (!empty($users)) {
            $configuracion->users()->sync($users);
        }

        // Si se marca como activa, desactivar las demás del mismo tipo
        if ($configuracion->es_activa) {
            $configuracion->activar();
        }

        // Si se marca como predeterminada, quitar predeterminada a las demás del mismo tipo
        if ($configuracion->es_predeterminada) {
            $configuracion->establecerPredeterminada();
        }

        // Cargar relaciones
        $configuracion->load(['sucursales', 'users']);

        return response()->json([
            'success' => true,
            'message' => 'Configuración creada exitosamente',
            'data' => $configuracion
        ], 201);
    }

    /**
     * Actualizar una configuración existente
     */
    public function update(Request $request, $id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);
        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        $request->validate([
            'sucursales' => 'sometimes|nullable|array',
            'sucursales.*' => 'integer|exists:sucursales,id',
            'users' => 'sometimes|nullable|array',
            'users.*' => 'integer|exists:users,id',
            'nombre' => 'sometimes|required|string|max:100',
            'tipo_impresion' => 'sometimes|required|in:ticket,vale,datos_compra,etiquetas,otros',
            'ancho_papel' => 'sometimes|required|integer|min:50|max:200',
            'alto_papel' => 'sometimes|integer|min:0|max:500',
            'margen_superior' => 'sometimes|numeric|min:0|max:50',
            'margen_inferior' => 'sometimes|numeric|min:0|max:50',
            'margen_izquierdo' => 'sometimes|numeric|min:0|max:50',
            'margen_derecho' => 'sometimes|numeric|min:0|max:50',
            'fuente_principal' => 'sometimes|required|string|max:50',
            'tamano_fuente_principal' => 'sometimes|required|integer|min:8|max:72',
            'tamano_fuente_titulo' => 'sometimes|required|integer|min:8|max:72',
            'tamano_fuente_subtitulo' => 'sometimes|required|integer|min:8|max:72',
            'tamano_fuente_detalle' => 'sometimes|required|integer|min:8|max:72',
            'color_texto' => 'sometimes|required|string|regex:/^#[0-9A-Fa-f]{6}$/',
            'peso_fuente' => 'sometimes|required|in:normal,bold,lighter,bolder',
            'interlineado' => 'sometimes|required|numeric|min:0|max:3.0',
            'alineacion_titulo' => 'sometimes|required|in:left,center,right',
            'alineacion_texto' => 'sometimes|required|in:left,center,right',
            'alineacion_empresa' => 'sometimes|required|in:left,center,right',
            'alineacion_direccion' => 'sometimes|required|in:left,center,right',
            'alineacion_folio_fecha' => 'sometimes|required|in:left,center,right',
            'alineacion_total' => 'sometimes|required|in:left,center,right',
            'alineacion_footer' => 'sometimes|required|in:left,center,right',
            'mostrar_logo' => 'sometimes|boolean',
            'mostrar_fecha' => 'sometimes|boolean',
            'mostrar_hora' => 'sometimes|boolean',
            'mostrar_cliente' => 'sometimes|boolean',
            'mostrar_empleado' => 'sometimes|boolean',
            'mostrar_observaciones' => 'sometimes|boolean',
            'separador_lineas' => 'sometimes|string|max:10',
            'padding_celda' => 'sometimes|numeric|min:0|max:20',
            'ancho_tabla' => 'sometimes|integer|min:50|max:100',
            'ancho_contenido_porcentaje' => 'sometimes|integer|min:50|max:100',
            'ancho_cuerpo_porcentaje' => 'sometimes|integer|min:50|max:100',
            'es_activa' => 'sometimes|boolean',
            'es_predeterminada' => 'sometimes|boolean',
            'es_impresion_directa' => 'sometimes|boolean',
        ]);

        // Determinar si es_impresion_directa está activo (del request o del valor actual)
        $esImpresionDirecta = $request->has('es_impresion_directa') 
            ? (bool)$request->es_impresion_directa 
            : $configuracion->es_impresion_directa;

        // Si es impresión directa, hacer obligatorios los campos relacionados
        $additionalRules = [];
        if ($esImpresionDirecta) {
            $additionalRules['ip_impresora'] = 'required|string|max:255';
            $additionalRules['ngrok_key'] = 'required|string|max:255';
            $additionalRules['users'] = 'required|array|min:1';
            $additionalRules['users.*'] = 'integer|exists:users,id';
        } else {
            $additionalRules['ip_impresora'] = 'sometimes|nullable|string|max:255';
            $additionalRules['ngrok_key'] = 'sometimes|nullable|string|max:255';
        }

        if (!empty($additionalRules)) {
            $request->validate($additionalRules, [
                'ip_impresora.required' => 'El campo Nombre de la impresora es requerido',
                'ngrok_key.required' => 'El campo Ngrok Key es requerido',
                'users.required' => 'El campo Usuarios es requerido',
            ]);
        }
        
        // Manejar flags especiales por separado para evitar desactivaciones accidentales
        $data = $request->all();
        $esActiva = array_key_exists('es_activa', $data) ? (bool)$data['es_activa'] : null;
        $esPredeterminada = array_key_exists('es_predeterminada', $data) ? (bool)$data['es_predeterminada'] : null;
        $sucursales = $data['sucursales'] ?? null;
        $users = $data['users'] ?? null;

        // Quitar flags y arrays del update normal
        unset($data['es_activa'], $data['es_predeterminada'], $data['sucursales'], $data['users']);

        // Actualizar solo campos no especiales
        $configuracion->update($data);

        // Sincronizar sucursales si se proporcionaron
        if ($sucursales !== null) {
            $configuracion->sucursales()->sync($sucursales);
        }

        // Sincronizar usuarios si se proporcionaron
        if ($users !== null) {
            $configuracion->users()->sync($users);
        }

        // Actualizar es_activa si fue enviado explícitamente
        if (!is_null($esActiva)) {
            if ($esActiva) {
                // Activa esta y desactiva las demás del mismo tipo
                $configuracion->activar();
            } else {
                // Solo desactivar esta
                $configuracion->update(['es_activa' => false]);
            }
        }

        // Actualizar es_predeterminada si fue enviado explícitamente
        if (!is_null($esPredeterminada)) {
            if ($esPredeterminada) {
                // Establecer como predeterminada y quitar a las demás
                $configuracion->establecerPredeterminada();
            } else {
                // Quitar predeterminada de esta
                $configuracion->update(['es_predeterminada' => false]);
            }
        }

        // Cargar relaciones
        $configuracion->load(['sucursales', 'users']);

        return response()->json([
            'success' => true,
            'message' => 'Configuración actualizada exitosamente',
            'data' => $configuracion
        ]);
    }

    /**
     * Eliminar una configuración
     */
    public function destroy($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        // No permitir eliminar la configuración predeterminada
        if ($configuracion->es_predeterminada) {
            return response()->json([
                'success' => false,
                'message' => 'No se puede eliminar la configuración predeterminada'
            ], 400);
        }

        $configuracion->delete();

        return response()->json([
            'success' => true,
            'message' => 'Configuración eliminada exitosamente'
        ]);
    }

    /**
     * Activar una configuración
     */
    public function activar($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        $configuracion->activar();

        return response()->json([
            'success' => true,
            'message' => 'Configuración activada exitosamente',
            'data' => $configuracion
        ]);
    }

    /**
     * Establecer como predeterminada
     */
    public function establecerPredeterminada($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        $configuracion->establecerPredeterminada();

        return response()->json([
            'success' => true,
            'message' => 'Configuración establecida como predeterminada',
            'data' => $configuracion
        ]);
    }

    /**
     * Duplicar una configuración
     */
    public function duplicar($id): JsonResponse
    {
        $configuracionOriginal = ConfigImpresion::find($id);

        if (!$configuracionOriginal) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        $nuevaConfiguracion = $configuracionOriginal->replicate();
        $nuevaConfiguracion->nombre = $configuracionOriginal->nombre . ' (Copia)';
        $nuevaConfiguracion->es_activa = false;
        $nuevaConfiguracion->es_predeterminada = false;
        $nuevaConfiguracion->save();

        return response()->json([
            'success' => true,
            'message' => 'Configuración duplicada exitosamente',
            'data' => $nuevaConfiguracion
        ], 201);
    }

    /**
     * Obtener estilos CSS para una configuración
     */
    public function getEstilos($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        return response()->json([
            'success' => true,
            'data' => [
                'css' => $configuracion->getEstilosCSS(),
                'configuracion' => $configuracion
            ]
        ]);
    }

     /**
     * Obtener configuración de impresión directa
     */
    public function getConfigImpresionDirecta(): JsonResponse
    {
        $imprimirDirecto = env('IMPRIMIR_DIRECTO', false) === true || env('IMPRIMIR_DIRECTO', 'false') === 'true';
        $endpointUrl = env('IMPRESION_ENDPOINT_URL', 'http://localhost:8081/api');

        return response()->json([
            'success' => true,
            'data' => [
                'imprimir_directo' => $imprimirDirecto,
                'endpoint_url' => $endpointUrl
            ]
        ]);
    }

    /**
     * Enviar prueba de impresión directa
     */
    public function enviarPrueba($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        // Validar que tenga los campos necesarios
        if (!$configuracion->es_impresion_directa) {
            return response()->json([
                'success' => false,
                'message' => 'Esta configuración no está configurada para impresión directa'
            ], 400);
        }

        if (!$configuracion->ngrok_key) {
            return response()->json([
                'success' => false,
                'message' => 'La configuración no tiene una key de ngrok configurada'
            ], 400);
        }

        try {
            // Obtener los túneles de ngrok con reintentos
            $publicUrl = $this->obtenerTunelNgrokConReintentos($configuracion->ngrok_key);
            
            if (!$publicUrl) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se pudo obtener un túnel activo de ngrok después de varios intentos'
                ], 400);
            }

            // Construir la URL del endpoint de prueba para ticket
            $endpointUrl = rtrim($publicUrl, '/') . '/api/imprimir-ticket';

            // Calcular anchoPapel (convertir de mm a píxeles aproximados, o usar 600 por defecto)
            $anchoPapel = $configuracion->ancho_papel ? (int)($configuracion->ancho_papel * 7.5) : 600;
            if ($anchoPapel < 200) $anchoPapel = 200;
            if ($anchoPapel > 1000) $anchoPapel = 1000;

            // Generar contenido de prueba para el ticket
            $contenidoTicket = $this->generarContenidoTicketPrueba();

            // Intentar hacer una petición de prueba al endpoint con reintentos
            $datosEnvio = [
                'nombreImpresora' => $configuracion->ip_impresora,
                'contenido' => $contenidoTicket,
                'tipoTicket' => 'Ticket',
                'anchoPapel' => $anchoPapel,
                'incluirImagen' => true
            ];

            $testResponse = $this->enviarPeticionConReintentos($endpointUrl, $datosEnvio);

            if ($testResponse['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Se pudo enviar la impresión correctamente'
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $testResponse['message'] ?? 'No se pudo acceder al dominio de la impresora ' . $endpointUrl,
                    'error' => $testResponse['error'] ?? null,
                    'endpoint_url' => $endpointUrl,
                    'status_code' => $testResponse['status_code'] ?? 400
                ], 400);
            }

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            return response()->json([
                'success' => false,
                'message' => 'No se pudo conectar al servicio de ngrok o al dominio de la impresora',
                'error' => $e->getMessage()
            ], 503);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error al enviar la prueba',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Enviar prueba de impresión de vale
     */
    public function enviarPruebaVale($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        // Validar que tenga los campos necesarios
        if (!$configuracion->es_impresion_directa) {
            return response()->json([
                'success' => false,
                'message' => 'Esta configuración no está configurada para impresión directa'
            ], 400);
        }

        if (!$configuracion->ngrok_key) {
            return response()->json([
                'success' => false,
                'message' => 'La configuración no tiene una key de ngrok configurada'
            ], 400);
        }

        try {
            // Obtener los túneles de ngrok con reintentos
            $publicUrl = $this->obtenerTunelNgrokConReintentos($configuracion->ngrok_key);
            
            if (!$publicUrl) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se pudo obtener un túnel activo de ngrok después de varios intentos'
                ], 400);
            }

            // Construir la URL del endpoint de prueba de vale
            $endpointUrl = rtrim($publicUrl, '/') . '/api/imprimir-vale';

            // Fabricar datos de prueba para el endpoint de ngrok
            $fechaVigencia = now()->addMonths(3)->format('d-m-Y'); // Vigencia de 3 meses desde hoy
            $folioPrueba = 'VALE-' . strtoupper(uniqid()); // Folio único de prueba
            
            // Calcular anchoPapel desde la configuración (convertir de mm a píxeles)
            $anchoPapel = $configuracion->ancho_papel ? (int)($configuracion->ancho_papel * 7.5) : 600;
            // Asegurar que esté en el rango válido
            if ($anchoPapel < 200) $anchoPapel = 200;
            if ($anchoPapel > 1000) $anchoPapel = 1000;

            // Preparar los datos para enviar al endpoint de ngrok
            $datosEnvio = [
                'nombreImpresora' => $configuracion->ip_impresora,
                'anchoPapel' => $anchoPapel,
                'incluirImagen' => true,
                'folio' => $folioPrueba,
                'vigencia' => $fechaVigencia,
                'tratamiento' => 'Tratamiento de Prueba - ' . $configuracion->nombre
            ];

            // Intentar hacer una petición de prueba al endpoint con reintentos
            $testResponse = $this->enviarPeticionConReintentos($endpointUrl, $datosEnvio);

            if ($testResponse['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Se pudo enviar la impresión correctamente'
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $testResponse['message'] ?? 'No se pudo acceder al dominio de la impresora ' . $endpointUrl,
                    'error' => $testResponse['error'] ?? null,
                    'endpoint_url' => $endpointUrl,
                    'status_code' => $testResponse['status_code'] ?? 400
                ], 400);
            }

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            return response()->json([
                'success' => false,
                'message' => 'No se pudo conectar al servicio de ngrok o al dominio de la impresora',
                'error' => $e->getMessage()
            ], 503);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error al enviar la prueba de vale',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Enviar prueba de impresión de etiquetas
     */
    public function enviarPruebaEtiquetas($id): JsonResponse
    {
        $configuracion = ConfigImpresion::find($id);

        if (!$configuracion) {
            return response()->json([
                'success' => false,
                'message' => 'Configuración no encontrada'
            ], 404);
        }

        // Validar que tenga los campos necesarios
        if (!$configuracion->es_impresion_directa) {
            return response()->json([
                'success' => false,
                'message' => 'Esta configuración no está configurada para impresión directa'
            ], 400);
        }

        if (!$configuracion->ngrok_key) {
            return response()->json([
                'success' => false,
                'message' => 'La configuración no tiene una key de ngrok configurada'
            ], 400);
        }

        try {
            // Obtener los túneles de ngrok con reintentos
            $publicUrl = $this->obtenerTunelNgrokConReintentos($configuracion->ngrok_key);
            
            if (!$publicUrl) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se pudo obtener un túnel activo de ngrok después de varios intentos'
                ], 400);
            }

            // Construir la URL del endpoint de prueba de etiquetas
            $endpointUrl = rtrim($publicUrl, '/') . '/api/imprimir-prueba-tspl';

            // Generar código de barras de prueba
            $codigoBarras = '1234567890123456';

            // Preparar los datos para enviar al endpoint
            $datosEnvio = [
                'nombreImpresora' => $configuracion->ip_impresora,
                'codigoBarras' => $codigoBarras
            ];

            // Intentar hacer una petición de prueba al endpoint con reintentos
            $testResponse = $this->enviarPeticionConReintentos($endpointUrl, $datosEnvio);

            if ($testResponse['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Se pudo enviar la impresión correctamente'
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $testResponse['message'] ?? 'No se pudo acceder al dominio de la impresora ' . $endpointUrl,
                    'error' => $testResponse['error'] ?? null,
                    'endpoint_url' => $endpointUrl,
                    'status_code' => $testResponse['status_code'] ?? 400
                ], 400);
            }

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            return response()->json([
                'success' => false,
                'message' => 'No se pudo conectar al servicio de ngrok o al dominio de la impresora',
                'error' => $e->getMessage()
            ], 503);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error al enviar la prueba de etiquetas',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Generar contenido de prueba para ticket
     */
    private function generarContenidoTicketPrueba(): string
    {
        $fecha = now()->format('d-m-Y H:i A');
        $folio = 'F-' . rand(10, 99) . ' - ' . $fecha;
        
        return "Paseo Usumacinta No. 923, Col. Linda Vista.\n" .
               "                   C.P. 86050                   \n" .
               "             {$folio}             \n" .
               "------------------------------------------------\n" .
               "Producto                      Cant.   precio\n" .
               "------------------------------------------------\n" .
               "MARINE PLASMA FRECH SERUM 50 ml.\n" .
               "                              1       \$1,525.00\n" .
               "------------------------------------------------\n" .
               "Total:                                \$1,525.00\n" .
               "================================================\n" .
               "            ¡GRACIAS POR SU VISITA!            \n" .
               "           ESTE COMPROBANTE NO TIENE            \n" .
               "                 VALIDEZ FISCAL                 \n" .
               "         POR FAVOR REVISE SUS PRODUCTOS         \n" .
               "              YA QUE NO SE ACEPTAN              \n" .
               "         RECLAMACIONES NI DEVOLUCIONES          \n" .
               "================================================\n";
    }

    /**
     * Obtener túnel de ngrok con reintentos (máximo 3 intentos: 1 inicial + 2 reintentos)
     */
    private function obtenerTunelNgrokConReintentos($ngrokKey, $maxIntentos = 3): ?string
    {
        $ultimoError = null;
        
        for ($intento = 1; $intento <= $maxIntentos; $intento++) {
            try {
                // Esperar un poco antes de reintentar (excepto en el primer intento)
                if ($intento > 1) {
                    sleep(2); // Esperar 2 segundos entre reintentos
                }

                $ngrokResponse = Http::timeout(60)
                    ->withHeaders([
                        'Authorization' => 'Bearer ' . $ngrokKey,
                        'ngrok-version' => '2'
                    ])
                    ->get('https://api.ngrok.com/tunnels');

                if ($ngrokResponse->successful()) {
                    $ngrokData = $ngrokResponse->json();

                    // Verificar que haya túneles disponibles
                    if (isset($ngrokData['tunnels']) && !empty($ngrokData['tunnels'])) {
                        $tunnel = $ngrokData['tunnels'][0];
                        $publicUrl = $tunnel['public_url'] ?? null;

                        if ($publicUrl) {
                            return $publicUrl;
                        }
                    }
                } else {
                    $ultimoError = [
                        'message' => 'No se pudo conectar con la API de ngrok',
                        'error' => $ngrokResponse->json() ?? $ngrokResponse->body(),
                        'status_code' => $ngrokResponse->status()
                    ];
                }
            } catch (\Illuminate\Http\Client\ConnectionException $e) {
                $ultimoError = [
                    'message' => 'Error de conexión con ngrok',
                    'error' => $e->getMessage()
                ];
            } catch (\Exception $e) {
                $ultimoError = [
                    'message' => 'Error inesperado al obtener túnel de ngrok',
                    'error' => $e->getMessage()
                ];
            }
        }

        // Si llegamos aquí, todos los intentos fallaron
        return null;
    }

    /**
     * Enviar petición HTTP con reintentos (máximo 3 intentos: 1 inicial + 2 reintentos)
     */
    private function enviarPeticionConReintentos($endpointUrl, $datosEnvio, $maxIntentos = 3): array
    {
        $ultimoError = null;
        
        for ($intento = 1; $intento <= $maxIntentos; $intento++) {
            try {
                // Esperar un poco antes de reintentar (excepto en el primer intento)
                if ($intento > 1) {
                    sleep(2); // Esperar 2 segundos entre reintentos
                }

                $testResponse = Http::timeout(30)
                    ->withHeaders([
                        'Accept' => 'application/json',
                        'Content-Type' => 'application/json'
                    ])
                    ->post($endpointUrl, $datosEnvio);

                if ($testResponse->successful()) {
                    return [
                        'success' => true,
                        'data' => $testResponse->json()
                    ];
                } else {
                    $ultimoError = [
                        'success' => false,
                        'message' => 'No se pudo acceder al dominio de la impresora ' . $endpointUrl,
                        'error' => $testResponse->json() ?? $testResponse->body(),
                        'status_code' => $testResponse->status()
                    ];
                }
            } catch (\Illuminate\Http\Client\ConnectionException $e) {
                $ultimoError = [
                    'success' => false,
                    'message' => 'No se pudo conectar al dominio de la impresora',
                    'error' => $e->getMessage(),
                    'status_code' => 503
                ];
            } catch (\Exception $e) {
                $ultimoError = [
                    'success' => false,
                    'message' => 'Error inesperado al enviar la petición',
                    'error' => $e->getMessage(),
                    'status_code' => 500
                ];
            }
        }

        // Si llegamos aquí, todos los intentos fallaron
        return $ultimoError ?? [
            'success' => false,
            'message' => 'Error desconocido después de varios intentos',
            'error' => null,
            'status_code' => 500
        ];
    }

    /**
     * Imprimir ticket de una venta usando impresora directa configurada
     */
    public function imprimirTicket(Request $request, $ventaId): JsonResponse
    {
        try {
            $venta = \App\Models\Venta::with([
                'sucursal',
                'cliente',
                'ventaDetalle.producto',
                'ventaDetalle.tratamiento',
                'ventaDetalle.vale'
            ])->find($ventaId);

            if (!$venta) {
                return response()->json([
                    'success' => false,
                    'message' => 'Venta no encontrada'
                ], 404);
            }

            // Obtener usuario y sucursal del request
            $userId = $request->user()->id;
            $sucursalId = $venta->sucursal_id;

            // Buscar configuración directa para ticket
            $configuracion = ConfigImpresion::getConfigDirecta('ticket', $userId, $sucursalId);

            if (!$configuracion) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se encontró una impresora directa configurada para este usuario y sucursal',
                    'fallback' => true
                ], 404);
            }

            // Validar que tenga los campos necesarios
            if (!$configuracion->ngrok_key) {
                return response()->json([
                    'success' => false,
                    'message' => 'La configuración no tiene una key de ngrok configurada'
                ], 400);
            }

            // Obtener los túneles de ngrok con reintentos
            $publicUrl = $this->obtenerTunelNgrokConReintentos($configuracion->ngrok_key);
            
            if (!$publicUrl) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se pudo obtener un túnel activo de ngrok después de varios intentos'
                ], 400);
            }

            // Construir la URL del endpoint
            $endpointUrl = rtrim($publicUrl, '/') . '/api/imprimir-ticket';

            // Generar contenido del ticket desde la venta
            $contenidoTicket = $this->generarContenidoTicketDesdeVenta($venta);

            // Calcular anchoPapel (convertir de mm a píxeles aproximados)
            $anchoPapel = $configuracion->ancho_papel ? (int)($configuracion->ancho_papel * 7.5) : 600;
            if ($anchoPapel < 200) $anchoPapel = 200;
            if ($anchoPapel > 1000) $anchoPapel = 1000;

            // Preparar los datos para enviar
            $datosEnvio = [
                'nombreImpresora' => $configuracion->ip_impresora,
                'contenido' => $contenidoTicket,
                'tipoTicket' => 'Ticket',
                'anchoPapel' => $anchoPapel,
                'incluirImagen' => true
            ];

            // Intentar hacer la petición con reintentos
            $testResponse = $this->enviarPeticionConReintentos($endpointUrl, $datosEnvio);

            if ($testResponse['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Se pudo enviar la impresión correctamente'
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $testResponse['message'] ?? 'No se pudo acceder al dominio de la impresora',
                    'error' => $testResponse['error'] ?? null,
                    'endpoint_url' => $endpointUrl,
                    'status_code' => $testResponse['status_code'] ?? 400
                ], 400);
            }

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            return response()->json([
                'success' => false,
                'message' => 'No se pudo conectar al servicio de ngrok o al dominio de la impresora',
                'error' => $e->getMessage()
            ], 503);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error al enviar la impresión',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Imprimir vale usando impresora directa configurada
     */
    public function imprimirVale(Request $request, $valeId): JsonResponse
    {
        try {
            $vale = \App\Models\Vale::find($valeId);

            if (!$vale) {
                return response()->json([
                    'success' => false,
                    'message' => 'Vale no encontrado'
                ], 404);
            }

            // Buscar el detalle de venta relacionado para obtener el tratamiento
            $ventaDetalle = \App\Models\VentaDetalle::where('vale_id', $vale->id)
                ->with(['tratamiento', 'venta'])
                ->first();

            if (!$ventaDetalle || !$ventaDetalle->venta) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se encontró la venta relacionada al vale'
                ], 404);
            }

            // Obtener usuario y sucursal
            $userId = $request->user()->id;
            $sucursalId = $ventaDetalle->venta->sucursal_id;

            // Buscar configuración directa para vale
            $configuracion = ConfigImpresion::getConfigDirecta('vale', $userId, $sucursalId);

            if (!$configuracion) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se encontró una impresora directa configurada para este usuario y sucursal',
                    'fallback' => true
                ], 404);
            }

            // Validar que tenga los campos necesarios
            if (!$configuracion->ngrok_key) {
                return response()->json([
                    'success' => false,
                    'message' => 'La configuración no tiene una key de ngrok configurada'
                ], 400);
            }

            // Obtener los túneles de ngrok con reintentos
            $publicUrl = $this->obtenerTunelNgrokConReintentos($configuracion->ngrok_key);
            
            if (!$publicUrl) {
                return response()->json([
                    'success' => false,
                    'message' => 'No se pudo obtener un túnel activo de ngrok después de varios intentos'
                ], 400);
            }

            // Construir la URL del endpoint
            $endpointUrl = rtrim($publicUrl, '/') . '/api/imprimir-vale';

            // Obtener datos del vale
            $fechaVigencia = $vale->vigencia 
                ? date('d-m-Y', strtotime($vale->vigencia))
                : date('d-m-Y', strtotime('+31 days'));
            
            $folioPrueba = (string)$vale->id;
            
            $tratamiento = 'Vale de Tratamiento';
            if ($ventaDetalle && $ventaDetalle->tratamiento) {
                $tratamiento = $ventaDetalle->tratamiento->nombre ?? $ventaDetalle->tratamiento->tratamiento ?? $ventaDetalle->descripcion;
            } elseif ($ventaDetalle && $ventaDetalle->descripcion) {
                $tratamiento = $ventaDetalle->descripcion;
            }

            // Calcular anchoPapel (convertir de mm a píxeles aproximados)
            $anchoPapel = $configuracion->ancho_papel ? (int)($configuracion->ancho_papel * 7.5) : 600;
            if ($anchoPapel < 200) $anchoPapel = 200;
            if ($anchoPapel > 1000) $anchoPapel = 1000;

            // Preparar los datos para enviar
            $datosEnvio = [
                'nombreImpresora' => $configuracion->ip_impresora,
                'anchoPapel' => $anchoPapel,
                'incluirImagen' => true,
                'folio' => $folioPrueba,
                'vigencia' => $fechaVigencia,
                'tratamiento' => $tratamiento,
                'qrData' => $vale->token,
            ];

            // Intentar hacer la petición con reintentos
            $testResponse = $this->enviarPeticionConReintentos($endpointUrl, $datosEnvio);

            if ($testResponse['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Se pudo enviar la impresión correctamente'
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $testResponse['message'] ?? 'No se pudo acceder al dominio de la impresora',
                    'error' => $testResponse['error'] ?? null,
                    'endpoint_url' => $endpointUrl,
                    'status_code' => $testResponse['status_code'] ?? 400
                ], 400);
            }

        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            return response()->json([
                'success' => false,
                'message' => 'No se pudo conectar al servicio de ngrok o al dominio de la impresora',
                'error' => $e->getMessage()
            ], 503);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error al enviar la impresión',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Generar contenido de ticket desde una venta real
     */
    private function generarContenidoTicketDesdeVenta(\App\Models\Venta $venta): string
    {
        $lineas = [];
        $anchoTicket = 48;

        // Dirección de la sucursal (sin C.P. para no duplicar)
        if ($venta->sucursal && $venta->sucursal->direccion) {
            $direccion = preg_replace('/\s*,?\s*C\.?P\.?\s*\d{5}\s*/i', '', $venta->sucursal->direccion);
            $lineas[] = trim($direccion);
        }

        // Código postal centrado (extraído de la dirección)
        if ($venta->sucursal && $venta->sucursal->direccion && preg_match('/C\.?P\.?\s*(\d{5})/i', $venta->sucursal->direccion, $matches)) {
            $lineas[] = str_pad('C.P. ' . $matches[1], $anchoTicket, ' ', STR_PAD_BOTH);
        }

        // Folio y fecha (centrado como el CP)
        $fechaFormateada = $venta->fecha_registro
            ? date('d-m-Y h A', strtotime($venta->fecha_registro))
            : date('d-m-Y h A');
        $lineas[] = str_pad("F-{$venta->id} - {$fechaFormateada}", $anchoTicket, ' ', STR_PAD_BOTH);
        $lineas[] = "------------------------------------------------";
        $lineas[] = "Producto                      Cant.   precio";
        $lineas[] = "------------------------------------------------";

        // Detalles de productos
        foreach ($venta->ventaDetalle as $detalle) {
            $lineas[] = $detalle->descripcion;
            $lineas[] = "                              {$detalle->cantidad}       $" . number_format($detalle->total, 2, '.', ',');
        }
        
        // Total
        $lineas[] = "------------------------------------------------";
        $lineas[] = "Total:                                $" . number_format($venta->total, 2, '.', ',');
        $lineas[] = "================================================";
        $lineas[] = "            ¡GRACIAS POR SU VISITA!            ";
        $lineas[] = "           ESTE COMPROBANTE NO TIENE            ";
        $lineas[] = "                 VALIDEZ FISCAL                 ";
        $lineas[] = "         POR FAVOR REVISE SUS PRODUCTOS         ";
        $lineas[] = "              YA QUE NO SE ACEPTAN              ";
        $lineas[] = "         RECLAMACIONES NI DEVOLUCIONES          ";
        $lineas[] = "================================================";

        return implode("\n", $lineas);
    }
}
