import time

from django.core.management.base import BaseCommand
from django.utils import timezone

from api.logics import Logics
from api.models import Order


class Command(BaseCommand):
    help = "Follows all active orders and make them expire if needed."

    do_nothing = [
        Order.Status.UCA,
        Order.Status.EXP,
        Order.Status.DIS,
        Order.Status.CCA,
        Order.Status.PAY,
        Order.Status.SUC,
        Order.Status.FAI,
        Order.Status.MLD,
        Order.Status.TLD,
        Order.Status.WFR,
    ]

    def clean_orders(self):
        """Continuously checks order expiration times. If order
        has expires, it calls the logics module for expiration handling."""

        queryset = Order.objects.exclude(status__in=self.do_nothing)
        queryset = queryset.filter(
            expires_at__lt=timezone.now()
        )  # expires at lower than now

        debug = {}
        debug["num_expired_orders"] = len(queryset)
        debug["expired_orders"] = []
        debug["failed_order_expiry"] = []
        debug["reason_failure"] = []

        for idx, order in enumerate(queryset):
            context = str(order) + " was " + Order.Status(order.status).label
            try:
                if Logics.order_expires(order):  # Order send to expire here
                    debug["expired_orders"].append({idx: context})

            # It should not happen, but if it cannot locate the hold invoice
            # it probably was cancelled by another thread, make it expire anyway.
            except Exception as e:
                debug["failed_order_expiry"].append({idx: context})
                debug["reason_failure"].append({idx: str(e)})

                if "unable to locate invoice" in str(e):
                    self.stdout.write(str(e))
                    order.update_status(Order.Status.EXP)
                    debug["expired_orders"].append({idx: context})

        if debug["num_expired_orders"] > 0:
            self.stdout.write(str(timezone.now()))
            self.stdout.write(str(debug))

    def handle(self, *args, **options):
        """Never mind database locked error, keep going, print them out.
        Not an issue with PostgresQL"""
        try:
            while True:
                self.clean_orders()
                time.sleep(5)

        except Exception as e:
            if "database is locked" in str(e):
                self.stdout.write("database is locked")

            self.stdout.write(str(e))