import socket
import time
import random
import datetime
import threading

# --- Configuración del cliente ---
# Cambia estos valores para que coincidan con tu servidor
SERVER_IP = '10.2.12.105' 
SERVER_PORT = 9098

# --- Parámetros de envío ---
INTERVAL = 0.1  # Segundos entre cada envío
BUFFER_SIZE = 1024  # Tamaño del buffer para recibir datos
TERMINATOR = b'$' # El servidor termina sus mensajes con un '$'

def generate_report():
    """Genera la trama con datos dinámicos."""
    # Variable 1: Hexadecimal aleatorio de 4 dígitos
    random_int = random.randint(0, 65535)
    random_hex = f'{random_int:04x}'

    # Variable 2: Fecha y hora en formato AAAAMMDDHHMMSS
    now = datetime.datetime.now()
    timestamp = now.strftime('%Y%m%d%H%M%S')
    
    # Crea la cadena de mensaje usando las variables
    message_str = f'+RESP:GTFRI,271102,999999999999999,gv300w,14490,11,1,1,14.5,273,4.1,-58.668692,-34.476290,{timestamp},0722,0310,432B,1713D9B,00,27441.5,,,,88,220900,,,,20250818175517,{random_hex}$'

    # Convierte la cadena a bytes antes de enviarla
    return message_str.encode('utf-8')


# --- Función para simular múltiples clientes TCP con conexión persistente ---
def tcp_client_persistent(thread_id, num_packets=5):
    print(f"[Thread {thread_id}] Intentando conectar a {SERVER_IP}:{SERVER_PORT}...")
    s = None
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((SERVER_IP, SERVER_PORT))
        s.settimeout(10)
        print(f"[Thread {thread_id}] Conexión persistente establecida. Enviando {num_packets} paquetes...")

        for i in range(num_packets):
            message_bytes = generate_report()
            try:
                s.sendall(message_bytes)
                print(f"[Thread {thread_id}] Paquete {i+1} enviado. Esperando respuesta...")

                # --- Lógica de Recepción Mejorada con Terminador ---
                response_buffer = b''
                while TERMINATOR not in response_buffer:
                    part = s.recv(BUFFER_SIZE)
                    if not part:
                        print(f"[Thread {thread_id}] Conexión cerrada por el servidor.")
                        return  # Cierra el hilo
                    response_buffer += part
                
                if response_buffer:
                    print(f"[Thread {thread_id}] Bytes recibidos: {response_buffer}")
                    try:
                        decoded_response = response_buffer.decode('utf-8')
                        print(f"[Thread {thread_id}] Respuesta decodificada: {decoded_response}")
                    except UnicodeDecodeError:
                        print(f"[Thread {thread_id}] No se pudo decodificar la respuesta como UTF-8.")
                # --- Fin de la Lógica de Recepción Mejorada ---
                
                print(f"[Thread {thread_id}] Esperando {INTERVAL} segundos antes de enviar el siguiente paquete...")
                time.sleep(INTERVAL)

            except (BrokenPipeError, ConnectionResetError) as e:
                print(f"[Thread {thread_id}] ERROR: La conexión se cortó. {e}")
                break
            except socket.timeout:
                print(f"[Thread {thread_id}] ADVERTENCIA: Tiempo de espera agotado al recibir datos.")
            except Exception as e:
                print(f"[Thread {thread_id}] Ocurrió un error inesperado: {e}")
                break
    except ConnectionRefusedError:
        print(f"[Thread {thread_id}] ERROR: Conexión rechazada. Asegúrate de que el servidor esté activo y escuchando en {SERVER_IP}:{SERVER_PORT}")
    except Exception as e:
        print(f"[Thread {thread_id}] ERROR: No se pudo establecer la conexión: {e}")
    finally:
        if s:
            print(f"[Thread {thread_id}] Prueba finalizada. Cerrando conexión.")
            s.close()


if __name__ == "__main__":
    NUM_CLIENTS = 1
    PACKETS_PER_CLIENT = 1
    threads = []
    for t in range(NUM_CLIENTS):
        thread = threading.Thread(target=tcp_client_persistent, args=(t, PACKETS_PER_CLIENT))
        thread.start()
        threads.append(thread)
    for thread in threads:
        thread.join()