from celery import shared_task
from django.db.models import Q
from django.utils import timezone

from external_api.cdek import client as cdek_client, CDEKStatus
from external_api.currency import client as CurrencyAPIClient
from .models import Checklist, GlobalSettings


@shared_task
def check_cdek_status(order_id):
    obj = Checklist.objects.filter(id=order_id).first()
    if obj is None or obj.cdek_tracking is None or obj.status == Checklist.Status.COMPLETED:
        return

    # Get CDEK statuses
    statuses = cdek_client.get_order_statuses(obj.cdek_tracking)
    if not statuses:
        return

    old_status = obj.status
    new_status = obj.status
    if CDEKStatus.DELIVERED in statuses:
        new_status = Checklist.Status.COMPLETED
    elif CDEKStatus.READY_FOR_SHIPMENT_IN_SENDER_CITY in statuses:
        new_status = Checklist.Status.CDEK

    # Update status
    if old_status != new_status:
        print(f'Order [{obj.id}] status: {old_status} -> {new_status}')
        obj.status = new_status
        obj.save()

    return f"{old_status} —> {new_status}"


@shared_task
def schedule_cdek_status_update():
    qs = Checklist.objects.filter(
        Q(cdek_tracking__isnull=False) & Q(status__in=Checklist.Status.CDEK_READY_STATUSES)
    )

    order_count = len(qs)
    print(f'Scheduled to update {order_count} orders')

    # Spawn a sub-task for every order
    for obj in qs:
        check_cdek_status.delay(order_id=obj.id)

    return order_count


@shared_task(autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={'max_retries': 5})
def update_yuan_rate():
    # Get fresh rate from API
    rate = CurrencyAPIClient.get_cny_rate()
    if not rate:
        raise Exception("Failed to get yuan rate")

    print(f"Fetched new yuan rate: {rate}")

    # Save rate in DB for future usage
    settings = GlobalSettings.load()
    settings.yuan_rate = rate
    settings.yuan_rate_last_updated = timezone.now()
    settings.save()

    return rate
