import uasyncio as asyncio
from ST7735 import TFT, TFTColor
from sysfont import sysfont
from machine import SPI, Pin
import usocket as socket
import network
import os
import sdcard

class Conexion:
    def __init__(self, red, clave):
        network.WLAN(network.AP_IF).active(False)  # Deshabilitar AP
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)
        self.red = red
        self.clave = clave

    async def conectar(self):
        if not self.wlan.isconnected():
            print(f"Conectando a {self.red}...")
            self.wlan.connect(self.red, self.clave)
            await self.esperar()

    def estado(self):
        return self.wlan.ifconfig() if self.wlan.isconnected() else None

    async def esperar(self, tiempo_max=30):
        """Espera hasta conectar o agota el tiempo (segundos)"""
        while tiempo_max > 0:
            if self.wlan.isconnected():
                print(f"Conectado a {self.red}")
                print(f"IP: {self.wlan.ifconfig()[0]}")
                return True
            print("Esperando conexión...")
            await asyncio.sleep(5)
            tiempo_max -= 5
        print("Tiempo agotado. No se pudo conectar.")
        return False
    
    def configuracion(self):
        # Devuelve la configuración de red (dirección IP, máscara, gateway, DNS)
        return self.wlan.ifconfig()

    async def scan(self):
        return self.wlan.scan()  # Escanea redes disponibles

class Pantalla:
    def __init__(self):
        self.spi = SPI(2, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(17))
        self.tft = TFT(self.spi, 16, 15, 21)
        self.tft.initr()
        self.tft.rgb(True)
        self.backlight = Pin(15, Pin.OUT)  # Control del backlight
        self.backlight.value(1)  # Encender backlight

    async def escribir(self, texto):
        self.tft.fill(TFT.BLACK)
        self.tft.text((10, 10), texto, TFT.WHITE, sysfont, 1.5)
        await asyncio.sleep(1)

    async def mostrar_bmp(self, archivo):
        try:
            with open(archivo, 'rb') as f:
                if f.read(2) != b'BM':
                    print("Archivo no es BMP válido")
                    return

                f.read(8)
                offset = int.from_bytes(f.read(4), 'little')
                hdrsize = int.from_bytes(f.read(4), 'little')
                width = int.from_bytes(f.read(4), 'little')
                height = int.from_bytes(f.read(4), 'little')
                if int.from_bytes(f.read(2), 'little') != 1:
                    print("El número de planos no es 1")
                    return
                depth = int.from_bytes(f.read(2), 'little')
                if depth != 24 or int.from_bytes(f.read(4), 'little') != 0:
                    print("Solo se admiten BMP de 24 bits sin compresión")
                    return

                print("Tamaño original de la imagen:", width, "x", height)
                rowsize = (width * 3 + 3) & ~3

                if height < 0:
                    height = -height
                    flip = False
                else:
                    flip = True

                # Dimensiones del TFT
                TFT_WIDTH = 128
                TFT_HEIGHT = 160

                # Calcular factor de escala manteniendo la proporción
                scale = min(TFT_WIDTH / width, TFT_HEIGHT / height)
                new_width = int(width * scale)
                new_height = int(height * scale)

                # Calcular el offset para centrar la imagen
                x_offset = (TFT_WIDTH - new_width) // 2
                y_offset = (TFT_HEIGHT - new_height) // 2

                # Llenar la pantalla con negro antes de dibujar la imagen escalada
                self.tft.fill(TFT.BLACK)

                self.tft._setwindowloc((x_offset, y_offset), (x_offset + new_width - 1, y_offset + new_height - 1))

                for row in range(new_height):
                    src_row = int((height - 1 - row / scale) if flip else (row / scale))  # Escalado Y
                    pos = offset + int(src_row) * rowsize
                    f.seek(pos)

                    for col in range(new_width):
                        src_col = int(col / scale)  # Escalado X
                        f.seek(pos + src_col * 3)  # Mueve al píxel correcto
                        bgr = f.read(3)
                        color = TFTColor(bgr[2], bgr[1], bgr[0])
                        self.tft._pushcolor(color)

                    await asyncio.sleep(0)  # Permite que otras tareas se ejecuten

        except Exception as e:
            print("Error al mostrar la imagen BMP:", e)

    async def apagar(self):
        self.tft.fill(TFT.BLACK)  # Borra la pantalla
        self.backlight.value(0)  # Apagar la retroiluminación

class Tarjeta:
    def __init__(self):
        self.spi = SPI(1, baudrate=1000000, polarity=0, phase=0, sck=Pin(36), mosi=Pin(35), miso=Pin(37))
        self.cs = Pin(34, Pin.OUT)
        self.sd = sdcard.SDCard(self.spi, self.cs)
        os.mount(self.sd, "/sd")
        print("Tarjeta SD montada correctamente")

    async def escribir(self, archivo, texto):
        await asyncio.sleep(0)  # Simular operación no bloqueante
        with open("/sd/" + archivo, "w") as f:
            f.write(texto)

    async def leer(self, archivo):
        """Lee un archivo desde la tarjeta microSD y lo devuelve como string"""
        await asyncio.sleep(0)  # Simular operación no bloqueante
        ruta = "/sd/" + archivo
        if archivo not in os.listdir("/sd"):
            raise FileNotFoundError(f"Archivo {archivo} no encontrado en la SD")
        with open(ruta, "r") as f:
            return f.read()

    async def listar(self):
        """Lista los archivos disponibles en la microSD"""
        await asyncio.sleep(0)  # Simular operación no bloqueante
        try:
            return os.listdir("/sd")
        except Exception as e:
            print(f"Error al listar archivos: {e}")
            return []
        
        
