#  Copyright (C) 2021
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Vasya Svintsov <v.svintsov@techokert.ru>
import logging
import ssl
from dataclasses import dataclass
from enum import Enum
from typing import Union, List, Optional

from email.utils import make_msgid
import aiosmtplib
from http_tools.attached_file import AttachedFile

from ..email_client import EmailClient
from ...sending_result import SendingResult
from ...tools.generate_email_message import generate_message


logger = logging.getLogger(__name__)


class ConnectionType(str, Enum):
    SSL = "SSL"
    TLS = "TLS"
    STARTTLS = "STARTTLS"


class SMTPEmailClient(EmailClient):
    @dataclass
    class Config:
        server_hostname: str
        server_ssl_port: int
        username: str
        password: str
        connection_type: str = "TLS"  # SSL | TLS | STARTTLS
        domain_name: str | None = None

    def __init__(self, config: Config):
        self._config = config

        connection_type = self._config.connection_type.upper()
        self._use_tls = True if connection_type == ConnectionType.TLS else False
        self._start_tls = True if connection_type == ConnectionType.STARTTLS else False
        self._tls_context = ssl._create_stdlib_context() if connection_type != ConnectionType.SSL else None

    async def send(self,
                   to_recipients: Union[str, List[str]],
                   subject: str,
                   body: str,
                   source_email_account: str,
                   *,
                   source_email_account_name: Optional[str] = None,
                   attachments: Optional[List[AttachedFile]] = None,
                   cc_recipients: Optional[Union[str, List[str]]] = None,
                   bcc_recipients: Optional[Union[str, List[str]]] = None,
                   in_reply_to: Optional[str] = None,
                   references: Optional[str] = None
                   ) -> SendingResult:
        message_id = make_msgid(domain=self._config.domain_name)
        message = generate_message(source_email_account, to_recipients, subject, body,
                                   source_email_account_name=source_email_account_name,
                                   attachments=attachments,
                                   cc_recipients=cc_recipients,
                                   bcc_recipients=bcc_recipients,
                                   message_id=message_id,
                                   in_reply_to=in_reply_to,
                                   references=references)
        try:
            await aiosmtplib.send(
                message,
                hostname=self._config.server_hostname,
                port=self._config.server_ssl_port,
                use_tls=self._use_tls,
                start_tls=self._start_tls,
                username=self._config.username,
                password=self._config.password,
                tls_context=self._tls_context
            )
            logger.info(f"Email sent from {source_email_account} to {to_recipients} successfully.")
            result = SendingResult(True, message_id)
        except aiosmtplib.errors.SMTPException as er:
            logger.error(f"Email sent from {source_email_account} to {to_recipients} failed, because {repr(er)}.")
            result = SendingResult(False, message_id)
        return result
