#  Copyright (C) 2021
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Vasya Svintsov <v.svintsov@techokert.ru>

import logging
from dataclasses import dataclass
from io import BytesIO
from typing import Union, List, Optional
from asyncio import TimeoutError
from aiohttp import FormData, ClientConnectorError
from aiohttp.web_exceptions import HTTPError
from http_tools.attached_file import AttachedFile
from http_tools.http_server_connector import HttpServerConnector

from http_tools.mime_types import ContentType

from ..email_client import EmailClient
from ...exceptions import SendFailed
from ...sending_result import SendingResult


logger = logging.getLogger(__name__)


class HTTPEmailClient(EmailClient):
    URL = "/v1/email/send"

    @dataclass
    class Config(HttpServerConnector.Config):
        ...

    @dataclass
    class Context(HttpServerConnector.Context):
        ...

    def __init__(self, config: Config, context: Context) -> None:
        self._http_connector = HttpServerConnector(config, context)

    async def send(self,
                   to_recipients: Union[str, List[str]],
                   subject: str,
                   body: str,
                   source_email_account: Optional[str] = None,
                   *,
                   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
                   ) -> SendingResult:
        form_data = FormData()

        values = {"subject": subject, "body": body, "to_recipients": to_recipients}
        if source_email_account is not None:
            values["source_email_account"] = source_email_account

        if source_email_account_name is not None:
            values["source_email_account_name"] = source_email_account_name

        if cc_recipients is not None:
            values["cc_recipients"] = cc_recipients

        if bcc_recipients is not None:
            values["bcc_recipients"] = bcc_recipients

        form_data.add_field("values", values, content_type=ContentType.Json.value)

        for item, attachment in enumerate(attachments, 1) if attachments is not None else []:
            form_data.add_field(f'file_{item}', BytesIO(attachment.content), filename=attachment.filename)

        try:
            payload = await self._http_connector.post(path=self.URL, payload=form_data)
            sending_result = SendingResult(**payload["result"])
            if not sending_result.status:
                raise SendFailed("unsuccessful send in gateway")
            logger.info(f"Email sent from {source_email_account} to {to_recipients} successfully.")
            result = sending_result
        except (HTTPError, TimeoutError, SendFailed, ClientConnectorError) as er:
            logger.error(f"Email sent from {source_email_account} to {to_recipients} failed, because {repr(er)}.")
            result = SendingResult(False)
        return result
