
import string
from datetime import datetime, timedelta
from certidude import authority, config, mailer, const
from certidude.relational import RelationalMixin
from certidude.common import random

class TokenManager(RelationalMixin):
    SQL_CREATE_TABLES = "token_tables.sql"

    def consume(self, uuid):
        now = datetime.utcnow()
        retval = self.get(
            "select subject, mail, created, expires, profile from token where uuid = ? and created < ? and ? < expires and used is null",
            uuid,
            now + const.CLOCK_SKEW_TOLERANCE,
            now - const.CLOCK_SKEW_TOLERANCE)
        self.execute(
            "update token set used = ? where uuid = ?",
            now,
            uuid)
        return retval

    def issue(self, issuer, subject, subject_mail=None):
        # Expand variables
        subject_username = subject.name
        if not subject_mail:
            subject_mail = subject.mail

        # Generate token
        token = ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(32))
        token_created = datetime.utcnow()
        token_expires = token_created + config.TOKEN_LIFETIME

        self.sql_execute("token_issue.sql",
            token_created, token_expires, token,
            issuer.name if issuer else None,
            subject_username, subject_mail, "rw")

        # Token lifetime in local time, to select timezone: dpkg-reconfigure tzdata
        try:
            with open("/etc/timezone") as fh:
                token_timezone = fh.read().strip()
        except EnvironmentError:
            token_timezone = None

        router = sorted([j[0] for j in authority.list_signed(
                    common_name=config.SERVICE_ROUTERS)])[0]
        protocols = ",".join(config.SERVICE_PROTOCOLS)
        url = config.TOKEN_URL % locals()

        context = globals()
        context.update(locals())

        mailer.send("token.md", to=subject_mail, **context)
        return {
            "token": token,
            "url": url,
        }

    def list(self, expired=False, used=False, token=False):
        stmt = "select created as 'created[timestamp]', expires as 'expires[timestamp]', used as 'used[timestamp]', issuer, mail, subject"
        if token:
            stmt += ", uuid"
        stmt += " from token"
        where = []
        args = []
        if not expired:
            where.append(" expires > ?")
            args.append(datetime.utcnow())
        if not used:
            where.append(" used is null")
        if where:
            stmt = stmt + " where " + (" and ".join(where))
        stmt += " order by expires"

        return self.iterfetch(stmt, *args)

    def purge(self, all=False):
        stmt = "delete from token"
        args = []
        if not all:
            stmt += " where expires < ?"
            args.append(datetime.utcnow())
        return self.execute(stmt, *args)
