import json
import logging

from flask_mail import Message

import features

from app import mail, app, get_app_url
from util.jinjautil import get_template_env


logger = logging.getLogger(__name__)
template_env = get_template_env("emails")


class CannotSendEmailException(Exception):
  pass


class GmailAction(object):
  """ Represents an action that can be taken in Gmail in response to the email. """
  def __init__(self, metadata):
    self.metadata = metadata

  @staticmethod
  def confirm(name, url, description):
    return GmailAction({
      "@context": "http://schema.org",
      "@type": "EmailMessage",
      "action": {
        "@type": 'ConfirmAction',
        "name": name,
        "handler": {
          "@type": "HttpActionHandler",
          "url": get_app_url() + '/' + url
        }
      },
      "description": description
    })

  @staticmethod
  def view(name, url, description):
    return GmailAction({
      "@context": "http://schema.org",
      "@type": "EmailMessage",
      "action": {
        "@type": 'ViewAction',
        "name": name,
        "url": get_app_url() + '/' + url
      },
      "description": description
    })


def send_email(recipient, subject, template_file, parameters, action=None):
  app_title = app.config['REGISTRY_TITLE_SHORT']
  app_url = get_app_url()

  def app_link_handler(url=None):
    return app_url + '/' + url if url else app_url

  app_logo = app.config.get('ENTERPRISE_LOGO_URL', 'https://quay.io/static/img/quay-logo.png')

  parameters.update({
    'subject': subject,
    'app_logo': app_logo,
    'app_url': app_url,
    'app_title': app_title,
    'hosted': features.BILLING,
    'app_link': app_link_handler,
    'action_metadata': json.dumps(action.metadata) if action else None
  })

  rendered_html = template_env.get_template(template_file + '.html').render(parameters)

  msg = Message('[%s] %s' % (app_title, subject), recipients=[recipient])
  msg.html = rendered_html

  try:
    mail.send(msg)
  except Exception as ex:
    logger.exception('Error while trying to send email to %s', recipient)
    raise CannotSendEmailException(ex.message)

def send_password_changed(username, email):
  send_email(email, 'Account password changed', 'passwordchanged', {
    'username': username
  })

def send_email_changed(username, old_email, new_email):
  send_email(old_email, 'Account e-mail address changed', 'emailchanged', {
    'username': username,
    'new_email': new_email
  })

def send_change_email(username, email, token):
  send_email(email, 'E-mail address change requested', 'changeemail', {
    'username': username,
    'token': token
  })

def send_confirmation_email(username, email, token):
  action = GmailAction.confirm('Confirm E-mail', 'confirm?code=' + token,
                               'Verification of e-mail address')

  send_email(email, 'Please confirm your e-mail address', 'confirmemail', {
    'username': username,
    'token': token
  }, action=action)

def send_repo_authorization_email(namespace, repository, email, token):
  action = GmailAction.confirm('Verify E-mail', 'authrepoemail?code=' + token,
                               'Verification of e-mail address')

  subject = 'Please verify your e-mail address for repository %s/%s' % (namespace, repository)
  send_email(email, subject, 'repoauthorizeemail', {
    'namespace': namespace,
    'repository': repository,
    'token': token
  }, action=action)


def send_org_recovery_email(org, admin_users):
  subject = 'Organization %s recovery' % (org.username)
  send_email(org.email, subject, 'orgrecovery', {
    'organization': org.username,
    'admin_usernames': [user.username for user in admin_users],
  })


def send_recovery_email(email, token):
  action = GmailAction.view('Recover Account', 'recovery?code=' + token,
                            'Recovery of an account')

  subject = 'Account recovery'
  send_email(email, subject, 'recovery', {
    'email': email,
    'token': token
  }, action=action)

def send_payment_failed(email, username):
  send_email(email, 'Subscription Payment Failure', 'paymentfailure', {
    'username': username
  })

def send_org_invite_email(member_name, member_email, orgname, team, adder, code):
  action = GmailAction.view('Join %s' % team, 'confirminvite?code=' + code,
                            'Invitation to join a team')

  send_email(member_email, 'Invitation to join team', 'teaminvite', {
    'inviter': adder,
    'token': code,
    'organization': orgname,
    'teamname': team
  }, action=action)


def send_invoice_email(email, contents):
  # Note: This completely generates the contents of the email, so we don't use the
  # normal template here.
  msg = Message('Quay payment received - Thank you!', recipients=[email])
  msg.html = contents
  mail.send(msg)


# INTERNAL EMAILS BELOW

def send_subscription_change(change_description, customer_id, customer_email, quay_username):
  SUBSCRIPTION_CHANGE_TITLE = 'Subscription Change - {0} {1}'
  SUBSCRIPTION_CHANGE = """
  Change: {0}<br>
  Customer id: <a href="https://manage.stripe.com/customers/{1}">{1}</a><br>
  Customer email: <a href="mailto:{2}">{2}</a><br>
  Quay user or org name: {3}<br>
  """

  title = SUBSCRIPTION_CHANGE_TITLE.format(quay_username, change_description)
  msg = Message(title, recipients=['stripe@quay.io'])
  msg.html = SUBSCRIPTION_CHANGE.format(change_description, customer_id, customer_email,
                                        quay_username)
  mail.send(msg)