#!/usr/bin/env python

import __main__
# This is going to require sqlalchemy 0.8 sooner than later.
__main__.__requires__ = __requires__ = ["tahrir-api", "sqlalchemy>=0.7"];
import pkg_resources
pkg_resources.require(__requires__)

import os
import datetime
import time
import urllib
import socket
import logging
import re

from tahrir_api.dbapi import TahrirDatabase
import transaction

log = logging.getLogger()
logging.basicConfig()

import fedmsg
import fedmsg.config

fm_config = fedmsg.config.load_config()
fm_config['cert_prefix'] = 'fedbadges'
fm_config['name'] = 'relay_inbound'
fm_config['active'] = True
fedmsg.init(**fm_config)

import fedbadges.utils

import ldap
import ldap.sasl
from ldap.controls.libldap import SimplePagedResultsControl

LDAP_CONF = "/etc/openldap/ldap.conf"


class LDAPClient(object):

    def __init__(self):
        self.config = {}
        self.conn = None
        self._read_config()

    def _read_config(self):
        conf_re = re.compile(r"^([A-Z_]+)\s+(.+)$")
        with open(LDAP_CONF) as cf:
            for line in cf:
                mo = conf_re.match(line.strip())
                if mo is None:
                    continue
                variable = mo.group(1)
                value = mo.group(2)
                self.config[variable] = value

    def connect(self):
        self.conn = ldap.initialize(self.config["URI"].split(" ")[0])
        self.conn.protocol_version = 3
        self.conn.sasl_interactive_bind_s('', ldap.sasl.gssapi())

    def search(self, base, filters, attrs):
        page_size = 1000
        base_dn = "{base},{main_base}".format(base=base,main_base=self.config['BASE'])
        page_cookie = ""
        while True:
            page_control = SimplePagedResultsControl(
                criticality=False, size=page_size, cookie=page_cookie
            )
            msgid = self.conn.search_ext(
                base_dn,
                ldap.SCOPE_SUBTREE,
                filters,
                attrlist=attrs,
                serverctrls=[page_control],
            )
            rtype, rdata, rmsgid, serverctrls = self.conn.result3(msgid)
            for dn, obj in rdata:
                yield obj
            for ctrl in serverctrls:
                if isinstance(ctrl, SimplePagedResultsControl):
                    page_cookie = ctrl.cookie
                    break
            if not page_cookie:
                break


def get_fas_userlist(threshold):
    os.environ["KRB5_CLIENT_KTNAME"] = fm_config.get("keytab")
    ldap_client = LDAPClient()
    ldap_client.connect()
    filters = "(&(fasCreationTime<={})(objectclass=fasUser))".format(threshold.strftime("%Y%m%d%H%M%SZ"))
    response = ldap_client.search(base="cn=users,cn=accounts", filters=filters, attrs=["uid", "memberof"])
    for res in response:
        groups = []
        for groupdn in res.get("memberof", []):
            groupdn = groupdn.decode("ascii")
            if not groupdn.endswith(",cn=groups,cn=accounts,{}".format(ldap_client.config['BASE'])):
                continue
            groupname = groupdn.split(",")[0].split("=")[1]
            if groupname == "ipausers":
                continue  # Assume all groups are FAS groups except this one
            groups.append(groupname)
        yield {"username": res["uid"][0].decode("ascii"), "groups": groups}


def main():
    global http_client
    now = datetime.datetime.utcnow()
    year = datetime.timedelta(days=365.5)
    mapping = {
        'egg': year * 1,
        'embryo': year * 2,
        'tadpole': year * 3,
        'tadpole-with-legs': year * 5,
        'froglet': year * 7,
        'adult-frog': year * 10,
    }

    # First, some validation that the badge ids actually exist.
    for badge_id, delta in mapping.items():
        badge = tahrir.get_badge(badge_id=badge_id)
        assert(badge.id)

    # Then, query IPA for users created before the threshold
    for badge_id, delta in mapping.items():
        badge = tahrir.get_badge(badge_id=badge_id)
        threshold = now - delta
        for person in get_fas_userlist(threshold):
            if len(person["groups"]) < 2:
                continue
            hit_em_up(badge, person)


def hit_em_up(badge, fas_user):
    email = fas_user["username"] + "@fedoraproject.org"
    user = tahrir.get_person(email)

    if not user:
        return

    if tahrir.assertion_exists(badge.id, email):
        print email, "already has", badge.id, "skipping."
        return

    time.sleep(1)
    print "awarding", badge.id, "to", email
    try:
        transaction.begin()
        tahrir.add_assertion(badge.id, email, None)
        transaction.commit()
    except Exception as e:
        transaction.abort()
        print "Failure:", e


if __name__ == '__main__':
    uri = fm_config['badges_global']['database_uri']
    tahrir = TahrirDatabase(
        uri,
        notification_callback=fedbadges.utils.notification_callback,
    )
    main()
