import logging
import time

from ...types import Timestamp
from ...util import none_or
from .collection import Collection

logger = logging.getLogger("mw.database.collections.users")


class Users(Collection):
    CREATION_ACTIONS = {'newusers', 'create', 'create2', 'autocreate',
                        'byemail'}

    def get(self, user_id=None, user_name=None):
        """
        Gets a single user row from the database.  Raises a :class:`KeyError`
        if a user cannot be found.

        :Parameters:
            user_id : int
                User ID
            user_name : str
                User's name

        :Returns:
            A user row.
        """
        user_id = none_or(user_id, int)
        user_name = none_or(user_name, str)

        query = """
            SELECT user.*
            FROM user
        """
        values = []

        if user_id is not None:
            query += """
                WHERE user_id = %s
            """
            values.append(user_id)

        elif user_name is not None:
            query += """
                WHERE user_name = %s
            """
            values.append(user_name)

        else:
            raise TypeError("Must specify a user identifier.")

        cursor = self.db.shared_connection.cursor()
        cursor.execute(
            query,
            values
        )

        for row in cursor:
            return row

        raise KeyError(user_id if user_id is not None else user_name)

    def query(self, registered_before=None, registered_after=None,
              before_id=None, after_id=None, limit=None,
              direction=None, self_created_only=False):
        """
        Queries users based on various filtering parameters.

        :Parameters:
            registered_before : :class:`mw.Timestamp`
                A timestamp to search before (inclusive)
            registered_after : :class:`mw.Timestamp`
                A timestamp to search after (inclusive)
            before_id : int
                A user_id to search before (inclusive)
            after_id : int
                A user_ud to search after (inclusive)
            direction : str
                "newer" or "older"
            limit : int
                Limit the results to at most this number
            self_creations_only : bool
                limit results to self_created user accounts

        :Returns:
            an iterator over ``user`` table rows
        """
        start_time = time.time()

        registered_before = none_or(registered_before, Timestamp)
        registered_after = none_or(registered_after, Timestamp)
        before_id = none_or(before_id, str)
        after_id = none_or(after_id, str)
        direction = none_or(direction, levels=self.DIRECTIONS)
        limit = none_or(limit, int)
        self_created_only = bool(self_created_only)

        query = """
            SELECT user.*
            FROM user
        """
        values = []

        if self_created_only:
            query += """
                INNER JOIN logging ON
                    log_user = user_id
                    log_type = "newusers" AND
                    log_action = "create"
            """

        query += "WHERE 1 "

        if registered_before is not None:
            query += "AND user_registration <= %s "
            values.append(registered_before.short_format())
        if registered_after is not None:
            query += "AND user_registration >= %s "
            values.append(registered_after.short_format())
        if before_id is not None:
            query += "AND user_id <= %s "
            values.append(before_id)
        if after_id is not None:
            query += "AND user_id >= %s "
            values.append(after_id)

        query += "GROUP BY user_id "  # In case of duplicate log events
        
        if direction is not None:
            if registered_before is not None or registered_after is not None:
                if direction == "newer":
                    query += "ORDER BY user_registration ASC "
                else:
                    query += "ORDER BY user_registration DESC "
            else:
                if direction == "newer":
                    query += "ORDER BY user_id ASC "
                else:
                    query += "ORDER BY user_id DESC "

        if limit is not None:
            query += "LIMIT %s "
            values.append(limit)

        cursor = self.db.shared_connection.cursor()
        cursor.execute(query, values)

        count = 0
        for row in cursor:
            yield row
            count += 1

        logger.debug("%s users queried in %s seconds" % (count, time.time() - start_time))
