import smtplib
import socket
import imaplib
import email
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formatdate


class MailClient:
    def __init__(self):
        """
        Inicializa el cliente de correo con la configuración del servidor.

        Atributos:
            server_ip (str): Dirección del servidor de correo.
            ports (dict): Diccionario con los puertos para SMTP e IMAP.
        """
        self.server_ip = "s1.ieslamar.org"
        self.ports = {
            "SMTP": 25,  # SMTP sin seguridad
            "SMTP-SUBMISSION": 587,  # SMTP autenticado sin SSL
            "IMAP": 143  # IMAP sin SSL
        }

    def check_smtp_connection(self, port):
        """
        Verifica si el servidor SMTP responde en un puerto específico.

        Args:
            port (int): Número del puerto a verificar.

        Returns:
            bool: `True` si la conexión es exitosa, `False` en caso contrario.
        """
        try:
            with socket.create_connection((self.server_ip, port), timeout=15):
                return True
        except (socket.timeout, ConnectionRefusedError):
            return False

    def send_email(self, sender_email, sender_password, recipient, subject, body):
        """
        Envía un correo utilizando el protocolo SMTP.

        Args:
            sender_email (str): Dirección de correo del remitente.
            sender_password (str): Contraseña del remitente.
            recipient (str): Dirección de correo del destinatario.
            subject (str): Asunto del correo.
            body (str): Cuerpo del correo.

        Returns:
            str: Mensaje indicando el resultado del envío.
        """
        try:
            # Crear el mensaje de correo
            message = MIMEMultipart()
            message["From"] = sender_email
            message["To"] = recipient
            message["Date"] = formatdate(localtime=True)
            message["Subject"] = subject
            message.attach(MIMEText(body, "plain", "utf-8"))

            # Lista de puertos disponibles para SMTP
            smtp_ports = [587, 25]  # Prioriza 587 y luego 25
            puerto_activo = None

            # Verificar qué puerto está disponible
            for smtp_port in smtp_ports:
                if self.check_smtp_connection(smtp_port):
                    puerto_activo = smtp_port
                    break

            if not puerto_activo:
                return "Error: No se pudo conectar con el servidor SMTP en los puertos (587, 25)."

            try:
                # Conectar al servidor SMTP
                with smtplib.SMTP(self.server_ip, puerto_activo, timeout=15) as server:
                    if puerto_activo == 587:
                        server.starttls()  # Activar TLS si se usa el puerto 587
                    server.login(sender_email, sender_password)  # Autenticación
                    server.sendmail(sender_email, recipient, message.as_string())  # Enviar el correo

                return f"Correo enviado correctamente a {recipient} usando el puerto {puerto_activo}"

            except smtplib.SMTPAuthenticationError:
                return "Error: Autenticación fallida. Verifica tu correo y contraseña."
            except smtplib.SMTPConnectError:
                return f"Error: No se pudo conectar al servidor en el puerto {puerto_activo}."
            except smtplib.SMTPException as e:
                return f"Error SMTP en el puerto {puerto_activo}: {str(e)}"

        except Exception as e:
            return f"Error inesperado al enviar el correo: {str(e)}"

    def fetch_emails(self, email_address, password):
        """
        Recupera los correos electrónicos de la bandeja de entrada usando IMAP.

        Args:
            email_address (str): Dirección de correo del usuario.
            password (str): Contraseña del usuario.

        Returns:
            list: Lista de tuplas con los correos (`email_id`, `subject`, `sender`).
            str: Mensaje de error si la autenticación falla.
        """
        try:
            # Conectar al servidor IMAP
            mail = imaplib.IMAP4(self.server_ip, self.ports["IMAP"])
            mail.login(email_address, password)
            mail.select("inbox")

            # Buscar todos los correos en la bandeja de entrada
            status, messages = mail.search(None, "ALL")
            email_ids = messages[0].split()
            emails = []

            # Obtener los últimos 10 correos
            for email_id in email_ids[-10:]:
                status, msg_data = mail.fetch(email_id, "(RFC822)")
                for response_part in msg_data:
                    if isinstance(response_part, tuple):
                        msg = email.message_from_bytes(response_part[1])

                        # Decodificar el asunto del correo
                        subject, encoding = email.header.decode_header(msg["Subject"])[0]
                        if isinstance(subject, bytes):
                            subject = subject.decode(encoding or "utf-8")

                        sender = msg.get("From")
                        emails.append((email_id, subject, sender))

            mail.logout()
            return emails

        except imaplib.IMAP4.error:
            return "Error: Fallo de autenticación en IMAP. Verifica tu correo y contraseña."
        except Exception as e:
            return f"Error al recibir los correos: {str(e)}"

    def delete_email(self, email_address, password, email_id):
        """
        Elimina un correo electrónico utilizando IMAP.

        Args:
            email_address (str): Dirección de correo del usuario.
            password (str): Contraseña del usuario.
            email_id (bytes): ID del correo a eliminar.

        Returns:
            str: Mensaje indicando si la eliminación fue exitosa o no.
        """
        try:
            # Conectar al servidor IMAP
            mail = imaplib.IMAP4(self.server_ip, self.ports["IMAP"])
            mail.login(email_address, password)
            mail.select("inbox")

            # Marcar el correo como eliminado
            mail.store(email_id, "+FLAGS", "\\Deleted")
            mail.expunge()  # Eliminar definitivamente los correos marcados
            mail.logout()

            return f"Correo con ID {email_id} eliminado correctamente."

        except imaplib.IMAP4.error:
            return "Error: Fallo de autenticación en IMAP. Verifica tu correo y contraseña."
        except Exception as e:
            return f"Error al eliminar el correo: {str(e)}"
