import asyncio
import aiosmtplib
import aioimaplib
import email
from email.header import decode_header
import mailparser
import logging
import time
import datetime

from aios import AgentTunnel,AgentMsg,ContactManager

from email.message import EmailMessage

logger = logging.getLogger(__name__)

class EmailTunnel(AgentTunnel):
    @classmethod
    def register_to_loader(cls):
        async def load_email_tunnel(config:dict) -> AgentTunnel:
            result_tunnel = EmailTunnel()
            if await result_tunnel.load_from_config(config):
                return result_tunnel
            else:
                return None
            
        AgentTunnel.register_loader("EmailTunnel",load_email_tunnel)

    async def load_from_config(self,config:dict)->bool:
        self.target_id = config["target"]
        self.tunnel_id = config["tunnel_id"]

        self.type = "EmailTunnel"
        self.email = config["email"]
        self.imap_server = config["imap"]
        s = self.imap_server.split(":")
        if len(s) == 2:
            self.imap_server = s[0]
            self.imap_port = int(s[1])

        self.smtp_server = config["smtp"]   
        s = self.smtp_server.split(":")
        if len(s) == 2:
            self.smtp_server = s[0]
            self.smtp_port = int(s[1])

        self.login_user = config["user"]
        self.login_password = config["password"]
        if config.get("folder") is not None:
            self.folder = config["folder"]
        if config.get("interval") is not None:
            self.check_interval = config["interval"]

        return True  
    
    def __init__(self) -> None:
        super().__init__()
        self.is_start = False
        self.read_email = {}
        self.folder = "INBOX"
        self.check_interval = 60

    async def on_new_email(self,mail:mailparser.MailParser) -> None:
        remote_email_addr = mail.from_[0][1]
        remote_user_name = remote_email_addr.split("@")[0] 
        agent_msg = self.conver_mail_to_agent_msg(mail)
        agent_msg.sender = remote_user_name
        agent_msg.target = self.target_id
        self.ai_bus.register_message_handler(remote_user_name, self._process_message)

        resp_msg = await self.ai_bus.send_message(agent_msg)
        if resp_msg is None:
            await self.reply_email(remote_email_addr,"Sorry, I can't understand your message","")
        else:
            if resp_msg.body_mime is None:
                await self.reply_email(remote_email_addr,"result",resp_msg.body)

    async def reply_email(self,target_email:str,title:str,msg:str) -> None:
        email_msg = EmailMessage()
        email_msg['Subject'] = f"Reply: {title}"
        email_msg['From'] = self.email
        email_msg['To'] = target_email
        email_msg.set_content(msg)

        await aiosmtplib.send(
            email_msg,
            hostname = self.smtp_server,
            port=self.smtp_port,
            username=self.login_user,
            password=self.login_password,
            )

    async def post_message(self, msg: AgentMsg) -> None:
        cm = ContactManager.get_instance()
        contact = cm.find_contact_by_name(msg.target)
        if contact is None:
            logger.error(f"can't find contact {msg.target} , post message through email_tunnel failed!")
            return
        
        target_email = contact.email
        if target_email is None:
            logger.error(f"contact {msg.target} has no email, post message through email_tunnel failed!")
            return
        
        email_msg = EmailMessage()
        email_msg['Subject'] = f"{msg.topic},From AIAgent {msg.sender}"
        email_msg['From'] = self.email
        email_msg['To'] = target_email
        email_msg.set_content(msg)

        await aiosmtplib.send(
            email_msg,
            hostname = self.smtp_server,
            port=self.smtp_port,
            username=self.login_user,
            password=self.login_password,
        )
        

    def conver_mail_to_agent_msg(self,mail:mailparser.MailParser) -> AgentMsg:
        msg = AgentMsg()
        msg.set("",self.target_id,mail.text_plain[0])
        msg.topic = "email"
        return msg

    async def check_email(self) -> None:
        self.last_check_num = 0
        self.last_check_time = datetime.datetime.now()
        while True:
            if self.is_start == False:
                return
            
            await asyncio.sleep(self.check_interval)
            imap_client = aioimaplib.IMAP4_SSL(host=self.imap_server,port=self.imap_port)
            await imap_client.wait_hello_from_server()
            await imap_client.login(self.login_user, self.login_password)

            date_since = self.last_check_time.strftime("%d-%b-%Y")
            
            await imap_client.select(self.folder)
            status, messages = await imap_client.search('UNSEEN',charset='US-ASCII')
            self.last_check_time = datetime.datetime.now()
            if status == "OK":
                message_numbers = messages[0].split()
                for num in message_numbers:
                    num = int(num)
                    if self.read_email.get(num) is not None:
                        continue
                    
                    status, email_data = await imap_client.fetch(str(num), "(RFC822)")
                    if status == "OK":
                        #r = email.message_from_bytes(email_data[1])
                        mail = mailparser.parse_from_bytes(email_data[1])
                        self.read_email[num] = mail
                        await self.on_new_email(mail)

            await imap_client.logout()

    async def start(self) -> bool:
        if self.is_start:
            logger.warning(f"tunnel {self.tunnel_id} is already started")
            return False
        self.is_start = True   

        asyncio.create_task(self.check_email())
        return True

    async def close(self) -> None:
        self.is_start = False

    async def _process_message(self, msg: AgentMsg) -> None:
        logger.warn(f"process message {msg.msg_id} from {msg.sender} to {msg.target}")

        
