import sys, email, email.header, email.utils, email.mime.text

from pyxolotl.encoder.base64 import Encoder
from pyxolotl.protocol.basic import Message


def decode_header(header):
    """Decode email header"""
    parts = [
        s.decode(charset or 'utf-8') if hasattr(s, 'decode') else s
        for s, charset in email.header.decode_header(header)
    ]
    return ' '.join(parts)


def parse_email(message):
    """Parse email message"""
    msg = email.message_from_string(message)
    parts = []
    for part in msg.walk():
        if part.get_content_type() == 'text/plain':
            parts.append(part.get_payload(decode=True).decode(
                part.get_content_charset() or 'utf-8'
            ))

    from_addr = email.utils.parseaddr(decode_header(msg['From']))
    to_addr = email.utils.getaddresses([decode_header(h) for h in msg.get_all('To')])
    subject = decode_header(msg['Subject'])
    return {'from': from_addr, 'to': to_addr, 'subject': subject, 'body': parts}


def create_email(from_addr, to_addr, subject, body, charset='utf-8'):
    """Create email message"""
    msg = email.mime.text.MIMEText(body, 'plain', charset)
    msg['Subject'] = email.header.Header(subject, charset)
    msg['From'] = email.header.Header(from_addr, charset)
    msg['To'] = email.header.Header(to_addr, charset)
    return msg


class Transport:
    """Email message transport"""
    def __init__(self, address, subject='', encoder=None):
        self.encoder = encoder or Encoder()
        self.address = address
        self.subject = subject

    def send(self, message):
        """Send email message (write it to stdout)"""
        if message:
            body = self.encoder.encode(message.serialize()).decode('ascii')
            email_message = create_email(self.address, message.identity, self.subject, body)
            sys.stdout.write(email_message.as_string())

    def receive(self, message=''):
        """Receive email message (read it from stdin)"""
        if not message:
            message = sys.stdin.read()

        email_message = parse_email(message)
        sender = email_message['from'][1]
        body = email_message['body'][0]
        if sender and body:
            return Message.from_raw(sender, self.encoder.decode(body.encode('ascii')))