# INSTRUKCJE IMPORTU #
import argparse
import sys
import configparser

import feedparser
import datetime
import delorean
import requests
from bs4 import BeautifulSoup
import mistune
import jinja2
from collections import namedtuple

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# WCZYTYWANIE SZABLONÓW #

# Zwróć uwagę na nazwę 'from_', co pozwala uniknąć zarezerwowanego słowa kluczowego
# z Pythona (from).
EmailConfig = namedtuple('EmailConfig', ['user', 'password', 'from_', 'to'])


# Pobieranie szablonów e-maili z dysku twardego.
EMAIL_TEMPLATE_FILE = 'email_template.md'
EMAIL_STYLING_FILE = 'email_styling.html'

with open(EMAIL_TEMPLATE_FILE) as md_file:
    EMAIL_TEMPLATE = md_file.read()

with open(EMAIL_STYLING_FILE) as html_file:
    EMAIL_STYLING = html_file.read()


def get_articles(keywords, feeds):
    '''    
    Pobieranie z kanałów informacyjnych listy artykułów zawierających
    podane słowa kluczowe.

    Każdy artykuł jest zwracany jako:

    (title, summary, link)
    '''
    articles = []

    for feed in feeds:
        rss = feedparser.parse(feed)
        updated_time = rss.get('updated', str(datetime.datetime.utcnow()))

        time_limit = delorean.parse(updated_time) - datetime.timedelta(days=7)
        for entry in rss.entries:
            # Normalizowanie czasu.
            entry_time = delorean.parse(entry.published)
            entry_time.shift('UTC')
            if entry_time < time_limit:
                # Pomijanie danej pozycji.
                continue

            # Pobieranie artykułu.
            response = requests.get(entry.link)
            article = BeautifulSoup(response.text, 'html.parser')
            article_reference = (article.title.string.strip(),
                                 entry.summary.strip(),
                                 entry.link)
            article_text = article.get_text()

            for keyword in keywords:
                if keyword.lower() in article_text.lower():
                    articles.append(article_reference)
                    break

    return articles


def compose_email_body(articles, keywords, feed_list):
    '''
    Na podstawie listy artykułów, słów kluczowych i kanałów informacyjnych
    uzupełniany jest szablon e-maili.

    Tworzenie listy w formacie dostosowanym do szablonu.
    '''    
    # Tworzenie listy artykułów.
    ARTICLE_TEMPLATE = '* **{title}** {summary}: {link}'
    article_list = [ARTICLE_TEMPLATE.format(title=title, summary=summary,
                                            link=link)
                    for title, summary, link in articles]

    data = {
        'article_list': '\n'.join(article_list),
        'keywords': ', '.join(keywords),
        'feed_list': ', '.join(feed_list),
    }
    text = EMAIL_TEMPLATE.format(**data)

    html_content = mistune.markdown(text)
    html = jinja2.Template(EMAIL_STYLING).render(content=html_content)

    return text, html


def send_email(email_config, text_body, html_body):
    '''
    Wysyłanie e-maila z tekstem i kodem HTML z użyciem parametrów
    zapisanych w zmiennej email_config.
    '''
    msg = MIMEMultipart('alternative')
    msg['Subject'] = 'Raport cotygodniowy'
    msg['From'] = email_config.from_
    msg['To'] = email_config.to

    part_plain = MIMEText(text_body, 'plain')
    part_html = MIMEText(html_body, 'html')

    msg.attach(part_plain)
    msg.attach(part_html)

    with smtplib.SMTP('smtp.gmail.com', 587) as server:
        server.starttls()
        server.login(email_config.user, email_config.password)
        server.sendmail(email_config.from_, [email_config.to], msg.as_string())


def main(keywords, feeds, email_config):
    articles = get_articles(keywords, feeds)
    text_body, html_body = compose_email_body(articles, keywords, feeds)
    send_email(email_config, text_body, html_body)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(type=argparse.FileType('r'), dest='config',
                        help='Plik konfiguracyjny')
    parser.add_argument('-o', dest='output', type=argparse.FileType('w'),
                        help='Plik na dane wyjściowe',
                        default=sys.stdout)

    args = parser.parse_args()
    config = configparser.ConfigParser()
    config.read_file(args.config)
    keywords = config['SEARCH']['keywords'].split(',')
    feeds = [feed.strip() for feed in config['SEARCH']['feeds'].split(',')]

    email_user = config['EMAIL']['user']
    email_password = config['EMAIL']['password']
    email_from = config['EMAIL']['from']
    email_to = config['EMAIL']['to']
    email_config = EmailConfig(email_user, email_password, email_from,
                               email_to)

    main(keywords, feeds, email_config)
