from core.Errors import InvoiceExpiredError, InvoicePaymentFailedError, InvoiceNotFoundError
from core.observers.ConnectionObserver import ConnectionObserver
from core.observers.InvoiceObserver import InvoiceObserver
from core.services.WebServiceApiService import WebServiceApiService
from typing import Optional
import time


class InvoiceController:

    @staticmethod
    def get(billing_code: str, proxies: Optional[dict] = None):
        return WebServiceApiService.get_invoice(billing_code, proxies)

    @staticmethod
    def handle_payment(billing_code: str, invoice_observer: InvoiceObserver = None, connection_observer: ConnectionObserver = None):

        from core.controllers.ConnectionController import ConnectionController
        return ConnectionController.with_preferred_connection(billing_code, task=InvoiceController.__handle_payment, invoice_observer=invoice_observer, connection_observer=connection_observer)

    @staticmethod
    def __handle_payment(billing_code: str, invoice_observer: Optional[InvoiceObserver] = None, proxies: Optional[dict] = None):

        invoice = None

        for index in range(1, 10):

            invoice = WebServiceApiService.get_invoice(billing_code, proxies)

            if invoice is None:
                time.sleep(5.0)
            else:
                break

        if invoice is None:
            raise InvoiceNotFoundError('The invoice in question could not be found.')

        invoice.status = 'new'

        if invoice_observer is not None:
            invoice_observer.notify('retrieved', invoice)

        while invoice.status == 'new':

            invoice = WebServiceApiService.get_invoice(billing_code, proxies)
            time.sleep(15.0)

        if invoice.status == 'expired':
            raise InvoiceExpiredError('The invoice in question has expired.')

        if invoice.status == 'processing':

            if invoice_observer is not None:
                invoice_observer.notify('processing', invoice)

            while invoice.status == 'processing':

                invoice = WebServiceApiService.get_invoice(billing_code, proxies)
                time.sleep(15.0)

        if invoice.status != 'settled':
            raise InvoicePaymentFailedError('The invoice payment has failed. Please contact support.')

        else:

            if invoice_observer is not None:
                invoice_observer.notify('settled', invoice)

            for attempt in range(1, 10):

                subscription = WebServiceApiService.get_subscription(billing_code, proxies)

                if subscription is not None:
                    return subscription

                else:
                    time.sleep(15.0)

            return None