import os.path
import ssl
import smtplib

# Email libaries
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formatdate

class EmailSender:
    def __init__(self, DashboardConfig):
        self.DashboardConfig = DashboardConfig

        if not os.path.exists('./attachments'):
            os.mkdir('./attachments')

        self.refresh_vals()

    def refresh_vals(self) -> None:
        self.Server = self.DashboardConfig.GetConfig("Email", "server")[1]
        self.Port = self.DashboardConfig.GetConfig("Email", "port")[1]

        self.Encryption = self.DashboardConfig.GetConfig("Email", "encryption")[1]
        self.AuthRequired = self.DashboardConfig.GetConfig("Email", "authentication_required")[1]
        self.Username = self.DashboardConfig.GetConfig("Email", "username")[1]
        self.Password = self.DashboardConfig.GetConfig("Email", "email_password")[1]

        self.SendFrom = self.DashboardConfig.GetConfig("Email", "send_from")[1]

    def is_ready(self) -> bool:
        self.refresh_vals()

        if self.AuthRequired:
            ready = all([
                self.Server, self.Port, self.Encryption,
                self.Username, self.Password, self.SendFrom
            ])
        else:
            ready = all([
                self.Server, self.Port, self.Encryption, self.SendFrom
            ])
        return ready

    def send(self, receiver, subject, body, includeAttachment: bool = False, attachmentName: str = "") -> tuple[bool, str | None]:
        if not self.is_ready():
            return False, "SMTP not configured"

        message = MIMEMultipart()
        message['Subject'] = subject
        message['From'] = self.SendFrom
        message["To"] = receiver
        message["Date"] = formatdate(localtime=True)
        message.attach(MIMEText(body, "plain"))

        if includeAttachment and len(attachmentName) > 0:
            attachmentPath = os.path.join('./attachments', attachmentName)

            if not os.path.exists(attachmentPath):
                return False, "Attachment does not exist"

            attachment = MIMEBase("application", "octet-stream")
            with open(os.path.join('./attachments', attachmentName), 'rb') as f:
                attachment.set_payload(f.read())

            encoders.encode_base64(attachment)
            attachment.add_header("Content-Disposition", f"attachment; filename= {attachmentName}",)
            message.attach(attachment)

        smtp = None
        try:
            context = ssl.create_default_context()
            if self.Encryption == "IMPLICITTLS":
                smtp = smtplib.SMTP_SSL(self.Server, port=int(self.Port), context=context)
            else:
                smtp = smtplib.SMTP(self.Server, port=int(self.Port))
            smtp.ehlo()

            # Configure SMTP encryption type
            if self.Encryption == "STARTTLS":
                smtp.starttls(context=context)
                smtp.ehlo()

            # Log into the SMTP server if required
            if self.AuthRequired:
                smtp.login(self.Username, self.Password)

            # Send the actual email from the SMTP object
            smtp.sendmail(self.SendFrom, receiver, message.as_string())
            return True, None

        except Exception as e:
            return False, f"Send failed | Reason: {e}"

        finally:
            if smtp:
                try:
                    smtp.quit()
                except Exception:
                    pass
