import mysql.connector
from datetime import timedelta, date


'''
promt utilizado
en mysql, tengo 2 servidores, A y B. El server B es una copia Por software del server A. En ellos tengo tablas llamadas LOG_XXXXX donde XXXX es un numero de hasta 16 digitos. El server primario es A y el secundario es B. en el server A se graban datos en las tablas hasta 200 dias de vida. en el server B se graban datos hasta 400 dias de vida. como son un espejo, en el server B hay iguales o mas tablas que en el server A, ademas es probable que en el server B una tabla, con el mismo nombre que en el server A, tengas mas datos que que tendra los 200 datos que se copiaron del server A mas quizas 100 datos mas historicos. Debido a una caida en el sofware que replica los datos necesito un script en python que haga lo siguiente:

1 verificar las tablas del server A y que exista en el server B. de no ser asi, crearla (junto con sus indices) en el server B.

2 si la tabla se creo en server B, copiar todos los datos de la tabla en server A

3 Si la tabla ya existia en server B. verificar si tienen los mismos datos. se podria hacer una verificacion por numero de mensaje en el campo reporte_mensaje y fecha GPS en el campo reporte_fechaGPS. Siempre el server B debe tener la misma o mas cantidad de mensajes que el server A. Aqui envio una imagen de la estructura de una tabla modelo.
'''

# --- Configuración de la conexión a los servidores ---
server_a_config = {
    'host': 'IP_DEL_SERVIDOR_A',
    'user': 'USUARIO_SERVIDOR_A',
    'password': 'PASSWORD_SERVIDOR_A',
    'database': 'NOMBRE_DE_LA_BASE_DE_DATOS',
}

server_b_config = {
    'host': 'IP_DEL_SERVIDOR_B',
    'user': 'USUARIO_SERVIDOR_B',
    'password': 'PASSWORD_SERVIDOR_B',
    'database': 'NOMBRE_DE_LA_BASE_DE_DATOS',
}

# --- Función para conectar a un servidor MySQL ---
def connect_to_server(config):
    try:
        cnx = mysql.connector.connect(**config)
        return cnx, cnx.cursor()
    except mysql.connector.Error as err:
        print(f"Error al conectar al servidor {config['host']}: {err}")
        return None, None

# --- Función para obtener la lista de tablas LOG_ en un servidor ---
def get_log_tables(cursor):
    cursor.execute("SHOW TABLES LIKE 'LOG_%'")
    tables = [table[0] for table in cursor.fetchall()]
    return tables

# --- Función para obtener la estructura de una tabla (columnas e índices) ---
def get_table_structure(cursor, table_name):
    cursor.execute(f"SHOW CREATE TABLE {table_name}")
    result = cursor.fetchone()
    if result:
        create_statement = result[1]
        columns = []
        indexes = []
        lines = create_statement.split('\n')
        for line in lines[1:-1]:  # Ignorar la primera y la última línea
            line = line.strip()
            if line.startswith('`'):
                parts = line.split('`')
                column_name = parts[1]
                columns.append(column_name)
            elif line.startswith('PRIMARY') or line.startswith('UNIQUE') or line.startswith('KEY'):
                indexes.append(line)
        return columns, indexes, create_statement
    return None, None, None

# --- Función para crear una tabla en el servidor B ---
def create_table_b(cursor_b, create_statement):
    try:
        cursor_b.execute(create_statement)
        print(f"Tabla creada en el servidor B: {create_statement.split(' ')[2]}")
        return True
    except mysql.connector.Error as err:
        print(f"Error al crear la tabla en el servidor B: {err}")
        return False

# --- Función para copiar todos los datos de la tabla A a la tabla B ---
def copy_data_a_to_b(cursor_a, cursor_b, table_name, columns):
    select_columns = ', '.join([f"`{col}`" for col in columns])
    query_a = f"SELECT {select_columns} FROM `{table_name}`"
    query_b = f"INSERT INTO `{table_name}` ({select_columns}) VALUES ({', '.join(['%s'] * len(columns))})"

    try:
        cursor_a.execute(query_a)
        data_to_insert = cursor_a.fetchall()
        if data_to_insert:
            cursor_b.executemany(query_b, data_to_insert)
            cnx_b.commit()
            print(f"Datos copiados de {table_name} (Servidor A) a {table_name} (Servidor B): {cursor_a.rowcount} registros.")
        else:
            print(f"No hay datos para copiar en {table_name} (Servidor A).")
        return True
    except mysql.connector.Error as err:
        cnx_b.rollback()
        print(f"Error al copiar datos de {table_name}: {err}")
        return False

# --- Función para verificar si las tablas tienen los mismos datos (por reporte_NroMensaje y Reporte_FechaGPS) ---
def verify_data(cursor_a, cursor_b, table_name):
    query_a = f"SELECT Reporte_NroMensaje, Reporte_FechaGPS FROM `{table_name}`"
    query_b = f"SELECT Reporte_NroMensaje, Reporte_FechaGPS FROM `{table_name}`"

    messages_a = set()
    messages_b = set()

    try:
        cursor_a.execute(query_a)
        for row in cursor_a.fetchall():
            if row[0] is not None and row[1] is not None:
                messages_a.add((str(row[0]), row[1].isoformat(timespec='microseconds') if hasattr(row[1], 'isoformat') else str(row[1])))

        cursor_b.execute(query_b)
        for row in cursor_b.fetchall():
            if row[0] is not None and row[1] is not None:
                messages_b.add((str(row[0]), row[1].isoformat(timespec='microseconds') if hasattr(row[1], 'isoformat') else str(row[1])))

        if messages_a.issubset(messages_b):
            print(f"La tabla '{table_name}' en el Servidor B contiene al menos los mismos datos que en el Servidor A.")
        else:
            missing_in_b = messages_a - messages_b
            print(f"Advertencia: La tabla '{table_name}' en el Servidor B NO contiene todos los datos del Servidor A. Faltan {len(missing_in_b)} registros.")
            # Opcional: Puedes implementar aquí la copia de los datos faltantes
            copy_missing_data(cursor_a, cursor_b, table_name, missing_in_b)

    except mysql.connector.Error as err:
        print(f"Error al verificar los datos de la tabla '{table_name}': {err}")

# --- Función opcional para copiar los datos faltantes (basado en la verificación) ---
def copy_missing_data(cursor_a, cursor_b, table_name, missing_data):
    if not missing_data:
        print(f"No hay datos faltantes para copiar en '{table_name}'.")
        return

    select_columns_query = f"SHOW COLUMNS FROM `{table_name}`"
    cursor_a.execute(select_columns_query)
    columns = [col[0] for col in cursor_a.fetchall()]
    select_columns_str = ', '.join([f"`{col}`" for col in columns])
    insert_placeholders = ', '.join(['%s'] * len(columns))
    insert_query = f"INSERT INTO `{table_name}` ({select_columns_str}) VALUES ({insert_placeholders})"

    copied_count = 0
    for msg, gps_date_str in missing_data:
        select_missing_query = f"SELECT {select_columns_str} FROM `{table_name}` WHERE Reporte_NroMensaje = %s AND Reporte_FechaGPS = %s"
        try:
            # Convertir la cadena de fecha GPS al formato adecuado para la consulta (si es necesario)
            cursor_a.execute(select_missing_query, (msg, gps_date_str))
            missing_rows = cursor_a.fetchall()
            if missing_rows:
                cursor_b.executemany(insert_query, missing_rows)
                copied_count += cursor_b.rowcount
        except mysql.connector.Error as err:
            print(f"Error al seleccionar o insertar datos faltantes para mensaje '{msg}' y fecha '{gps_date_str}': {err}")
            cnx_b.rollback()
            return

    if copied_count > 0:
        cnx_b.commit()
        print(f"Se copiaron {copied_count} registros faltantes a la tabla '{table_name}' en el Servidor B.")
    else:
        print(f"No se encontraron registros faltantes para copiar a la tabla '{table_name}' en el Servidor B (después de la verificación).")


if __name__ == "__main__":
    # Conectar a los servidores
    cnx_a, cursor_a = connect_to_server(server_a_config)
    cnx_b, cursor_b = connect_to_server(server_b_config)

    if cursor_a and cursor_b:
        # Obtener la lista de tablas LOG_ en el servidor A
        tables_a = get_log_tables(cursor_a)
        print(f"\nTablas LOG_ encontradas en el Servidor A: {tables_a}")

        # Obtener la lista de tablas LOG_ en el servidor B
        tables_b = get_log_tables(cursor_b)
        print(f"Tablas LOG_ encontradas en el Servidor B: {tables_b}\n")

        # Procesar cada tabla del servidor A
        for table_a in tables_a:
            if table_a not in tables_b:
                # 1. La tabla no existe en el servidor B, crearla y copiar datos
                columns_a, indexes_a, create_statement_a = get_table_structure(cursor_a, table_a)
                if create_statement_a:
                    if create_table_b(cursor_b, create_statement_a):
                        if columns_a:
                            copy_data_a_to_b(cursor_a, cursor_b, table_a, columns_a)
            else:
                # 3. La tabla existe en el servidor B, verificar si tienen los mismos datos
                print(f"\nVerificando datos de la tabla '{table_a}'...")
                verify_data(cursor_a, cursor_b, table_a)

        # Cerrar las conexiones
        if cnx_a:
            cnx_a.close()
        if cnx_b:
            cnx_b.close()
        print("\nProceso completado.")
    else:
        print("\nNo se pudo conectar a uno o ambos servidores. Por favor, revise la configuración.")