# Rozesílání e-mailových notifikací všeho druhu

import datetime
import email.message
import email.headerregistry
import subprocess
import textwrap
import urllib.parse

import mo.db as db
import mo.config as config
from mo.util import logger


def send_user_email(user: db.User, subject: str, body: str) -> bool:
    logger.info(f'Mail: "{subject}" -> {user.email}')

    mail_from = getattr(config, 'MAIL_FROM', None)
    if mail_from is None:
        logger.error('Mail: V configu chybí nastavení MAIL_FROM')
        return False

    msg = email.message.EmailMessage()
    msg['From'] = email.headerregistry.Address(
        display_name='Odevzdávací Systém MO',
        addr_spec=mail_from,
    )
    msg['To'] = [
        email.headerregistry.Address(
            display_name=user.full_name(),
            addr_spec=user.email,
        )
    ]
    msg['Reply-To'] = email.headerregistry.Address(
        display_name='Správce OSMO',
        addr_spec=config.MAIL_CONTACT,
    )
    msg['Subject'] = 'OSMO – ' + subject
    msg['Date'] = datetime.datetime.now()

    msg.set_content(body, cte='quoted-printable')

    mail_instead = getattr(config, 'MAIL_INSTEAD', None)
    if mail_instead is None:
        send_to = user.email
    else:
        send_to = mail_instead

    sm = subprocess.Popen(
        [
            '/usr/sbin/sendmail',
            '-oi',
            '-f',
            mail_from,
            send_to,
        ],
        stdin=subprocess.PIPE,
    )
    sm.communicate(msg.as_bytes())

    if sm.returncode != 0:
        logger.error('Mail: Sendmail failed with return code {}'.format(sm.returncode))
        return False

    return True


def activate_url(token: str) -> str:
    return config.WEB_ROOT + 'acct/activate?' + urllib.parse.urlencode({'token': token}, safe=':')


def confirm_url(type: str, token: str) -> str:
    return config.WEB_ROOT + f'acct/confirm/{type}?' + urllib.parse.urlencode({'token': token}, safe=':')


def contestant_list_url(contest: db.Contest, registered_only: bool) -> str:
    url = config.WEB_ROOT + f'org/contest/c/{contest.contest_id}/ucastnici'
    if registered_only:
        url += '?participation_state=registered'
    return url


def send_new_account_email(user: db.User, token: str) -> bool:
    return send_user_email(user, 'Založen nový účet', textwrap.dedent('''\
        Vítejte!

        Právě Vám byl založen účet v Odevzdávacím systému Matematické olympiády.
        Nastavte si prosím heslo na následující stránce:

                {}

        Váš OSMO
    '''.format(activate_url(token))))


def send_password_reset_email(user: db.User, token: str) -> bool:
    return send_user_email(user, 'Obnova hesla', textwrap.dedent('''\
        Někdo (pravděpodobně Vy) požádal o obnovení hesla k Vašemu účtu v Odevzdávacím
        systému Matematické olympiády. Heslo si můžete nastavit, případně požadavek
        zrušit, na následující stránce:

                {}

        Váš OSMO
    '''.format(confirm_url('p', token))))


def send_confirm_create_email(user: db.User, token: str) -> bool:
    return send_user_email(user, 'Založení účtu', textwrap.dedent('''\
        Někdo (pravděpodobně Vy) požádal o založení účtu s touto e-mailovou adresou
        v Odevzdávacím systému Matematické olympiády. Pokud účet chcete založit,
        následujte tento odkaz:

                {}

        Váš OSMO
    '''.format(confirm_url('r', token))))


def send_confirm_change_email(user: db.User, token: str) -> bool:
    return send_user_email(user, 'Změna e-mailové adresy', textwrap.dedent('''\
        Někdo (pravděpodobně Vy) požádal o nastavení e-mailové adresy k účtu
        v Odevzdávacím systému Matematické olympiády na tuto adresu.
        Pokud změnu chcete provést, následujte tento odkaz:

                {}

        Váš OSMO
    '''.format(confirm_url('e', token))))


def send_join_notify_email(dest: db.User, who: db.User, contest: db.Contest) -> bool:
    round = contest.round
    place = contest.place
    if contest.round.enroll_mode == db.RoundEnrollMode.confirm:
        confirm = 'Přihlášku je potřeba potvrdit v seznamu účastníků soutěže.'
        url = 'Přihlášky k potvrzení: ' + contestant_list_url(contest, True)
    else:
        confirm = 'Přihláška byla schválena automaticky.'
        url = 'Seznam účastníků: ' + contestant_list_url(contest, False)

    return send_user_email(dest, f'Nový účastník kategorie {round.category}', textwrap.dedent(f'''\
        Nový účastník se přihlásil do MO v oblasti, kterou garantujete.

        Jméno:      {who.full_name()}
        E-mail:     {who.email}
        Kategorie:  {round.category}
        Kolo:       {round.name}
        Místo:      {place.name}

        {confirm}

        {url}

        Váš OSMO
    '''))