from django.db import connection


def get_sql(sql, params):
    """
    Execute an SQL query and return the associated cursor.
    """
    cursor = connection.cursor()
    cursor.execute(sql, params)
    return cursor


def get_sql_count(sql, params):
    """
    Execute a count on SUB-SELECT and return the count.
    """
    cursor = get_sql('''SELECT COUNT(*) FROM (%s) AS CNT''' % sql, params)
    return cursor.fetchone()[0]


def get_sql_ids(sql, params):
    """
    Retrieve a list of numerical ids.
    """
    cursor = get_sql(sql, params)
    return (row[0] for row in cursor.fetchall())


def get_complex_join(qs, sql, params):
    ids = list(get_sql_ids(sql, params))
    return qs.filter(pk__in=ids)


def get_unseen_documents_count(related_users, user):
    query = GET_UNSEEN_DOCUMENTS_SQL % ('(%s)' % ', '.join(['%s'] * len(related_users)))
    return get_sql_count(
        query,
        (False,)
        + tuple(related_users.values_list('id', flat=True))
        + (user.pk, user.pk, False, user.pk, True),
    )


def get_documents(qs, related_users, user, outbox):
    query = GET_DOCUMENTS_SQL % ('(%s)' % ', '.join(['%s'] * len(related_users)))
    qs = get_complex_join(
        qs,
        query,
        (outbox,) + tuple(related_users.values_list('id', flat=True)) + (user.pk, False, user.pk, True),
    )
    qs = qs.prefetch_related('to_list', 'to_user', 'mailboxes__owner')
    qs = qs.extra(select={'seen': SEEN_DOCUMENT % user.pk})
    return qs


def get_trash_documents(qs, related_users, user, outbox):
    query = GET_TRASH_DOCUMENTS_SQL % ('(%s)' % ', '.join(['%s'] * len(related_users)))
    qs = get_complex_join(
        qs,
        query,
        (outbox,) + tuple(related_users.values_list('id', flat=True)) + (user.pk, False, user.pk, True),
    )
    qs = qs.prefetch_related('to_list', 'to_user', 'mailboxes__owner')
    return qs


GET_UNSEEN_DOCUMENTS_SQL = '''SELECT d.id
    FROM docbow_document AS d
    INNER JOIN docbow_mailbox AS mb
        ON mb.outbox = %%s AND mb.document_id = d.id AND mb.owner_id IN %s
    WHERE
        NOT EXISTS(SELECT 1 FROM docbow_deleteddocument dd WHERE dd.document_id = d.id AND dd.user_id = %%s)
        AND NOT EXISTS(SELECT 1 FROM docbow_seendocument sd WHERE sd.document_id = d.id AND sd.user_id = %%s)
        AND (d.private = %%s OR (mb.owner_id = %%s AND d.private = %%s))
    GROUP BY d.id, d.date
    ORDER BY d.date
    '''

GET_DOCUMENTS_SQL = '''SELECT d.id
    FROM docbow_document AS d
    INNER JOIN docbow_mailbox AS mb ON
        mb.outbox = %%s AND mb.document_id = d.id AND mb.owner_id IN %s
    WHERE
        NOT EXISTS(SELECT 1 FROM docbow_deleteddocument dd WHERE dd.document_id = d.id AND dd.user_id = %%s)
        AND (d.private = %%s OR (mb.owner_id = %%s AND d.private = %%s))
    GROUP BY d.id, d.date
    ORDER BY d.date'''


GET_TRASH_DOCUMENTS_SQL = '''SELECT d.id
    FROM docbow_document AS d
    INNER JOIN docbow_mailbox AS mb ON
        mb.outbox = %%s AND mb.document_id = d.id AND mb.owner_id IN %s
    LEFT JOIN docbow_deleteddocument AS dd ON
        dd.document_id = d.id AND dd.user_id = %%s AND dd.soft_delete
    WHERE (d.private = %%s OR (mb.owner_id = %%s AND d.private = %%s))
    GROUP BY d.id, d.date
    ORDER BY d.date'''


SEEN_DOCUMENT = '''SELECT COUNT(*) > 0
    FROM docbow_seendocument
    WHERE docbow_seendocument.document_id = docbow_document.id
    AND docbow_seendocument.user_id = %s'''
