from __future__ import absolute_import

import logging
from modularodm import Q

from website.app import init_app
from website.models import Node, User
from framework.mongo.utils import paginated
from scripts.analytics.base import SnapshotAnalytics

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)


# Modified from scripts/analytics/benchmarks.py
def get_enabled_authorized_linked(user_settings_list, has_external_account, short_name):
    """ Gather the number of users who have at least one node in each of the stages for an addon

    :param user_settings_list: list of user_settings for a particualr addon
    :param has_external_account: where addon is derrived from, determines method to load node settings
    :param short_name: short name of addon to get correct node_settings
    :return:  dict with number of users that have at least one project at each stage
    """
    from addons.forward.models import NodeSettings as ForwardNodeSettings

    num_enabled = 0  # of users w/ 1+ addon account connected
    num_authorized = 0  # of users w/ 1+ addon account connected to 1+ node
    num_linked = 0  # of users w/ 1+ addon account connected to 1+ node and configured

    # osfstorage and wiki don't have user_settings, so always assume they're enabled, authorized, linked
    if short_name == 'osfstorage' or short_name == 'wiki':
        num_enabled = num_authorized = num_linked = User.find(
                    Q('is_registered', 'eq', True) &
                    Q('password', 'ne', None) &
                    Q('merged_by', 'eq', None) &
                    Q('date_disabled', 'eq', None) &
                    Q('date_confirmed', 'ne', None)
                ).count()

    elif short_name == 'forward':
        num_enabled = num_authorized = ForwardNodeSettings.find().count()
        num_linked = ForwardNodeSettings.find(Q('url', 'ne', None)).count()

    else:
        for user_settings in paginated(user_settings_list):
            if has_external_account:
                if user_settings.has_auth:
                    num_enabled += 1
                    node_settings_list = [Node.load(guid).get_addon(short_name) for guid in user_settings.oauth_grants.keys()]
            else:
                num_enabled += 1
                node_settings_list = [Node.load(guid).get_addon(short_name) for guid in user_settings.nodes_authorized]
            if any([ns.has_auth for ns in node_settings_list if ns]):
                num_authorized += 1
                if any([(ns.complete and ns.configured) for ns in node_settings_list if ns]):
                    num_linked += 1
    return {
        'enabled': num_enabled,
        'authorized': num_authorized,
        'linked': num_linked
    }


class AddonSnapshot(SnapshotAnalytics):

    @property
    def collection_name(self):
        return 'addon_snapshot'

    def get_events(self, date=None):
        super(AddonSnapshot, self).get_events(date)

        from addons.base.models import BaseNodeSettings
        from website.settings import ADDONS_AVAILABLE

        counts = []
        addons_available = {k: v for k, v in [(addon.short_name, addon) for addon in ADDONS_AVAILABLE]}

        for short_name, addon in addons_available.iteritems():

            has_external_account = hasattr(addon.settings_models.get('node'), 'external_account')

            connected_count = 0
            deleted_count = 0
            disconnected_count = 0
            node_settings_model = addon.settings_models.get('node')
            if node_settings_model:
                for node_settings in paginated(node_settings_model):
                    if node_settings.owner and not node_settings.owner.is_bookmark_collection:
                        connected_count += 1
                deleted_count = addon.settings_models['node'].find(Q('deleted', 'eq', True)).count() if addon.settings_models.get('node') else 0
                if has_external_account:
                    disconnected_count = addon.settings_models['node'].find(Q('external_account', 'eq', None) & Q('deleted', 'ne', True)).count() if addon.settings_models.get('node') else 0
                else:
                    if addon.settings_models.get('node'):
                        for nsm in addon.settings_models['node'].find(Q('deleted', 'ne', True)):
                            if nsm.configured and not nsm.complete:
                                disconnected_count += 1
            total = connected_count + deleted_count + disconnected_count
            usage_counts = get_enabled_authorized_linked(addon.settings_models.get('user'), has_external_account, addon.short_name)

            counts.append({
                'provider': {
                    'name': short_name
                },
                'users': usage_counts,
                'nodes': {
                    'total': total,
                    'connected': connected_count,
                    'deleted': deleted_count,
                    'disconnected': disconnected_count
                }
            })

            logger.info(
                '{} counted. Users with a linked node: {}, Total connected nodes: {}.'.format(
                    addon.short_name,
                    usage_counts['linked'],
                    total
                )
            )
        return counts


def get_class():
    return AddonSnapshot


if __name__ == '__main__':
    init_app()
    addon_snapshot = AddonSnapshot()
    events = addon_snapshot.get_events()
    addon_snapshot.send_events(events)

@@ -3291,33 +3291,24 @@
 sattr(addon.
-settings_
 models.get('
@@ -3311,16 +3311,24 @@
 et('node
+settings
 '), 'ext
@@ -3477,33 +3477,24 @@
 del = addon.
-settings_
 models.get('
@@ -3497,16 +3497,24 @@
 et('node
+settings
 ')%0A     
@@ -3787,33 +3787,24 @@
 unt = addon.
-settings_
 models%5B'node
@@ -3795,32 +3795,40 @@
 don.models%5B'node
+settings
 '%5D.find(Q('delet
@@ -3858,33 +3858,24 @@
 () if addon.
-settings_
 models.get('
@@ -3870,32 +3870,40 @@
 models.get('node
+settings
 ') else 0%0A      
@@ -3980,33 +3980,24 @@
 unt = addon.
-settings_
 models%5B'node
@@ -3988,32 +3988,40 @@
 don.models%5B'node
+settings
 '%5D.find(Q('exter
@@ -4087,33 +4087,24 @@
 () if addon.
-settings_
 models.get('
@@ -4107,16 +4107,24 @@
 et('node
+settings
 ') else 
@@ -4172,33 +4172,24 @@
    if addon.
-settings_
 models.get('
@@ -4192,16 +4192,24 @@
 et('node
+settings
 '):%0A    
@@ -4241,33 +4241,24 @@
 sm in addon.
-settings_
 models%5B'node
@@ -4257,16 +4257,24 @@
 ls%5B'node
+settings
 '%5D.find(
@@ -4560,25 +4560,16 @@
 d(addon.
-settings_
 models.g
@@ -4576,16 +4576,24 @@
 et('user
+settings
 '), has_

Update AppConfig model access syntax