# -*- coding: utf-8 -*-
import six

from collections import defaultdict

from importlib import import_module

from django.core import exceptions
from django.conf import settings
from django.apps import apps

from . import settings as defaults


CLASS_PATH_ERROR = "django-discussions is unable to interpret settings value for %s. " "%s should be in the form of a tupple: " "('path.to.models.Class', 'app_label')."


def load_class(class_path, setting_name=None):
    """
    Loads a class given a class_path. The setting value may be a string or a
    tuple.

    The setting_name parameter is only there for pretty error output, and
    therefore is optional
    """
    if not isinstance(class_path, six.string_types):
        try:
            class_path, app_label = class_path
        except:
            if setting_name:
                raise exceptions.ImproperlyConfigured(
                    CLASS_PATH_ERROR % (setting_name, setting_name)
                )
            else:
                raise exceptions.ImproperlyConfigured(
                    CLASS_PATH_ERROR % ("this setting", "It")
                )

    try:
        class_module, class_name = class_path.rsplit(".", 1)
    except ValueError:
        if setting_name:
            txt = "%s isn't a valid module. Check your %s setting" % (
                class_path,
                setting_name,
            )
        else:
            txt = "%s isn't a valid module." % class_path
        raise exceptions.ImproperlyConfigured(txt)

    try:
        mod = import_module(class_module)
    except ImportError as e:
        if setting_name:
            txt = 'Error importing backend %s: "%s". Check your %s setting' % (
                class_module,
                e,
                setting_name,
            )
        else:
            txt = 'Error importing backend %s: "%s".' % (class_module, e)

        raise exceptions.ImproperlyConfigured(txt)

    try:
        clazz = getattr(mod, class_name)
    except AttributeError:
        if setting_name:
            txt = (
                'Backend module "%s" does not define a "%s" class. Check'
                " your %s setting" % (class_module, class_name, setting_name)
            )
        else:
            txt = 'Backend module "%s" does not define a "%s" class.' % (
                class_module,
                class_name,
            )
        raise exceptions.ImproperlyConfigured(txt)
    return clazz


def get_profile_model():
    """
    Return the model class for the currently-active user profile
    model, as defined by the ``AUTH_PROFILE_MODULE`` setting.

    :return: The model that is used as profile.

    """
    if (not hasattr(settings, "AUTH_PROFILE_MODULE")) or (
        not settings.AUTH_PROFILE_MODULE
    ):
        return None

    return apps.get_model(*settings.AUTH_PROFILE_MODULE.split("."))


def queryset_to_dict(qs, key="pk", singular=True):
    """
    Given a queryset will transform it into a dictionary based on ``key``.
    """
    if singular:
        result = {}
        for u in qs:
            result.setdefault(getattr(u, key), u)
    else:
        result = defaultdict(list)
        for u in qs:
            result[getattr(u, key)].append(u)
    return result


def get_model_string(model_name):
    """
    Returns the model string notation Django uses for lazily loaded ForeignKeys
    (eg 'auth.User') to prevent circular imports.

    This is needed to allow our crazy custom model usage.
    """
    setting_name = "DISCUSSIONS_%s_MODEL" % model_name.upper().replace("_", "")
    class_path = getattr(defaults, setting_name, None)

    if not class_path:
        return "discussions.%s" % model_name
    elif isinstance(class_path, basestring):
        parts = class_path.split(".")
        try:
            index = parts.index("models") - 1
        except ValueError:
            raise exceptions.ImproperlyConfigured(
                CLASS_PATH_ERROR % (setting_name, setting_name)
            )
        app_label, model_name = parts[index], parts[-1]
    else:
        try:
            class_path, app_label = class_path
            model_name = class_path.split(".")[-1]
        except:
            raise exceptions.ImproperlyConfigured(
                CLASS_PATH_ERROR % (setting_name, setting_name)
            )

    return "%s.%s" % (app_label, model_name)
