# 1. permissions.json
"""
{
    "mapping":{
        "c":"create",
        "r":"read",
        "u":"update",
        "d":"delete"
    },
    "group":{
        "admin":{
            "cart":"r,u,d,buy,send,telandc,read-pending,read-paid,read-bought",
            "province":"c,r,u,d",
            "district":"c,r,u,d",
            "sub_district":"c,r,u,d",
            "customer":"r,u,d,suspend",
            "admin":"c,r,u,d,suspend"
        },
        "operator":{
            "cart":"buy,r",
            "province":"r",
            "district":"r",
            "sub_district":"r"
        }
    }
}
"""

# app/management/commands/create_permissions.py

import os
import json

from django.db.models import Q
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import (User, Group, Permission)
from django.core.management.base import (BaseCommand, CommandError)

from apps.models_helper.address import (Province, District, SubDistrict)
from apps.models_helper.cart import Cart

PERMISSIONS_JSON_FILE = os.path.join(settings.BASE_DIR, 'permissions.json')


class Command(BaseCommand):
    """
    command to generate/recheck all groups & permissions
    which following `permissions.json` file.

    ./manage.py create_permissions
    """

    help = 'Command to generate groups and permissions for users'

    def add_message(self, message, status='success'):
        """ to add message for success or warning only """
        message = self.style.SUCCESS(message) \
            if status == 'success' \
            else self.style.WARNING(message)
        self.stdout.write(message)

    def load_json_file(self):
        """ load json file as dictionary """
        open_file = open(PERMISSIONS_JSON_FILE, 'r').read()
        return json.loads(open_file)

    def key_name_to_content_type(self, key_name):
        """
        parsing a `key_name` to `content_type` object.

        :param `key_name` is like 'cart', 'province', etc.
        """
        key_maps = {
            'admin': User,
            'operator': User,
            'customer': User,
            'cart': Cart,
            'province': Province,
            'district': District,
            'sub_district': SubDistrict
        }
        if key_name in key_maps.keys():
            class_name = key_maps.get(key_name)
            return ContentType.objects.get_for_model(class_name)

        # when `key_name` dosn't exist at `key_maps`
        raise Exception('You need to update `key_maps` in this file: %s' % __file__)

    def generate_permissions(self, key_name, str_permissions):
        """
        :param `key_name` is like "cart", "province", "admin", or etc.
        :param `str_permissions` is like "c,r,u,d,buy,send,telandc"

        parsing some access names:
            c: to create-<key_name>
            r: to read-<key_name>
            u: to update-<key_name>
            d: to delete-<key_name>

        return list objects of permissions.
        """
        list_permissions = str_permissions.split(',')
        json_file = self.load_json_file()
        mapping = json_file.get('mapping')
        new_permissions = []

        for permission in list_permissions:
            if permission in mapping.keys():
                permission = mapping.get(permission)

            code = '%s-%s' % (permission, key_name)
            name = 'can %s %s' % (permission, key_name)
            content_type = self.key_name_to_content_type(key_name)

            permission, truefalse = Permission.objects.get_or_create(codename=code, name=name,
                                                                     content_type=content_type)
            permission.save()
            new_permissions.append(permission)
        return new_permissions

    def check_group(self, group_name):
        """ to get or create the group """
        group, truefalse = Group.objects.get_or_create(name=group_name)
        group.save()
        return group

    def check_permissions(self):
        """
        to get or create the permissions,
        and register the permissions into groups.
        """
        group_names = self.load_json_file().get('group')

        for key_group_name, value_dict in group_names.items():
            permissions = []

            for key_name, str_permissions in value_dict.items():
                new_permissions = self.generate_permissions(key_name, str_permissions)
                permissions.extend(new_permissions)

            group = self.check_group(key_group_name)
            permissions = list(set(permissions))

            for permission in permissions:
                group.permissions.add(permission)

        self.add_message('Groups & Permissions successfully added!')

    def handle(self, *args, **kwargs):
        # noqa
        self.check_permissions()