from django.db.models import Q

from hookmigration.peewee_models import CustomersOrder
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
from hookmigration.models import Transient
from django.core.management import BaseCommand
from oscar.core.loading import get_model
from subscription.models import Subscription
from django.db import transaction
import crayons
from progressbar import ProgressBar
from django.utils import timezone

Product = get_model('catalogue', 'Product')
Category = get_model('catalogue', 'Category')
ProductAttribute = get_model('catalogue', 'ProductAttribute')
ProductAttributeValue = get_model('catalogue', 'ProductAttributeValue')
ProductClass = get_model('catalogue', 'ProductClass')
StockRecord = get_model('partner', 'StockRecord')
Partner = get_model('partner', 'Partner')
ProductImage = get_model('catalogue', 'ProductImage')
ProductCategory = get_model('catalogue', 'ProductCategory')
AttributeOption = get_model('catalogue', 'AttributeOption')
AttributeOptionGroup = get_model('catalogue', 'AttributeOptionGroup')
Country = get_model('address', 'Country')
Order = get_model('order', 'Order')
Line = get_model('order', 'Line')
LinePrice = get_model('order', 'LinePrice')
UserAddress = get_model('address', 'UserAddress')
ShippingAddress = get_model('order', 'ShippingAddress')

product_content_type = ContentType.objects.get_for_model(Product)
order_content_type = ContentType.objects.get_for_model(Order)
address_content_type = ContentType.objects.get_for_model(UserAddress)
shipping_address_content_type = ContentType.objects.get_for_model(ShippingAddress)
user_content_type = ContentType.objects.get_for_model(User)
subscription_content_type = ContentType.objects.get_for_model(Subscription)

pods_product_class = ProductClass.objects.get(slug='coffee-pods')
coffee_product_class = ProductClass.objects.get(slug='coffee-bag')


class Command(BaseCommand):
    help = 'Migrate all the subscriptions'

    ACTIVE = 'AC'
    SHIPPED = 'SH'
    PAUSED = 'PA'
    CANCELED = 'CA'
    ERROR = 'ER'
    DECLINED = 'DE'

    GRINDED = 'GR'
    WHOLEBEANS = 'WB'
    DRIP_BAGS = 'DR'
    BOTTLED = 'BO'
    BREW_BAG = 'BB'
    NESPRESSO = 'NE'  # ['NE', 'SP'] in fact
    SHOT_PODS = 'SP'
    PODS = 'PODS'

    """
    {'DR', 'GR', 'NE', 'PODS', 'SP', 'WB'}
    """

    NO_PRODUCT = set()

    NEW_STATUSES = {
        ACTIVE: Subscription.ACTIVE,
        PAUSED: Subscription.PAUSED,
        ERROR: Subscription.ERROR,
        DECLINED: Subscription.ERROR
    }

    PACKAGE_CHOICES = {
        GRINDED: 'Ground',
        WHOLEBEANS: 'Whole Beans',
        DRIP_BAGS: 'Drip Bags',
        BOTTLED: '',
        BREW_BAG: '',
        NESPRESSO: ''  # This will be the pods orders
    }

    WEIGHT = {
        '80': AttributeOption.objects.filter(option='80g').first(),
        '200': AttributeOption.objects.filter(option='200g').first(),
        '1000': AttributeOption.objects.filter(option='1kg').first(),
    }

    problem_users = []
    problem_addresses = []
    problem_products = []

    coffee_product_class = ProductClass.objects.filter(slug='coffee-bag').first()
    pods_product_class = ProductClass.objects.filter(slug='coffee-pods').first()

    def get_user(self, order):
        new_user_pk = Transient.objects.filter(content_type=user_content_type).filter(
            old_pk=order.customer.user_id)
        if not new_user_pk.exists():
            return None
        return User.objects.filter(pk=new_user_pk.first().new_pk)

    def get_address(self, order, user):
        if order.address:
            new_address_pk = Transient.objects.filter(content_type=address_content_type).filter(
                old_pk=order.address_id).first()
            return UserAddress.objects.get(pk=new_address_pk.new_pk)
        return UserAddress.objects.filter(user=user).first()

    def get_product(self, order):
        new_product_pk = Transient.objects.filter(content_type=product_content_type).filter(
            old_pk=order.coffee_id).first()
        try:
            product = Product.objects.filter(pk=new_product_pk.new_pk).prefetch_related('product_class').first()
        except Exception as e:
            print('=====================================================')
            print(order.coffee)
            print('=====================================================')
            exit()
        if product.product_class == self.coffee_product_class:
            # comb through children
            for child in product.children.filter(subscription=True).all():
                if str(child.attr.packaging) == self.PACKAGE_CHOICES[order.package]:
                    return child
        elif product.product_class == self.pods_product_class:
            return product.children.filter(subscription=True).first()
        print('========================================================================')
        print(order.coffee)
        print(order.package)
        print(self.PACKAGE_CHOICES[order.package])
        print(order.id)
        print(product)
        print(product.product_class)
        print('========================================================================')
        raise Exception('Non coffee and pod')

    def handle(self, *args, **options):
        # Move all the orders of status active, error and paused to the subscription table.c
        # If they are coffee, find the product based on the weight and packaaing. The next shipping date should follow.
        # if they are pods, just get the subscription pods.
        with transaction.atomic():
            orders = CustomersOrder.select().where(
                CustomersOrder.status.in_([self.ACTIVE, self.PAUSED, self.DECLINED])).where(
                CustomersOrder.recurrent == True).distinct()
            total = orders.count()
            finished = 0
            progress = ProgressBar(max_value=total)
            for order in orders:
                user = self.get_user(order)
                if not user or not user.exists():
                    self.problem_users.append(order)
                    continue
                user = user.first()
                address = self.get_address(order, user)
                if not address:
                    raise Exception('No address orderid - {}'.format(order.id))
                product = self.get_product(order)
                if not product:
                    raise Exception('No product order - {}'.format(order.id))

                # Add it to the subscriptions.

                subscription = Subscription(
                    user=user,
                    product=product,
                    interval=order.interval,
                    brewing_method=order.brew.name,
                    status=self.NEW_STATUSES[order.status],
                    next_order=timezone.localtime(order.shipping_date).date(),
                    shipping_address=address,
                    surprise=order.different,
                    created=timezone.localtime(order.date).date()
                )
                subscription.save()
                Transient.objects.create(
                    content_type=subscription_content_type,
                    old_pk=order.id,
                    new_pk=subscription.pk,
                    old_model=order.__class__.__name__
                )

                finished += 1
                progress.update(finished)
                # print("Finished {} of {}".format(crayons.red(finished), crayons.magenta(total)))

            print('=======================================================================================')
            print(crayons.red('Problem Products'))
            for order in self.problem_products:
                print(crayons.cyan(order.id), '-', order.coffee)
            print('=======================================================================================')

            print('=======================================================================================')
            print(crayons.red('Problem Addresses'))
            for order in self.problem_addresses:
                print(crayons.cyan(order.id), '-', order.coffee)
            print('=======================================================================================')

            print('=======================================================================================')
            print(crayons.red('Problem Users'))
            for order in self.problem_users:
                print(crayons.cyan(order.id), '-', order.coffee)
            print('=======================================================================================')
