<?php

namespace helpers;

use classes\economic;
use Exception;
use objects\collected_order_invoices_o;

class economic_tasks
{
    public function __construct()
    {
        // Define the error messages, if they are not already defined
        if (!defined("ERROR_MESSAGE_ECONOMIC_INVOICE_NOT_FOUND")) {
            define("ERROR_MESSAGE_ECONOMIC_INVOICE_NOT_FOUND", 'ECONOMIC_INVOICE_NOT_FOUND');
        }
        if (!defined("ERROR_MESSAGE_ECONOMIC_INVOICE_DRAFT_NOT_FOUND")) {
            define("ERROR_MESSAGE_ECONOMIC_INVOICE_DRAFT_NOT_FOUND", 'ECONOMIC_INVOICE_DRAFT_NOT_FOUND');
        }
    }

    /**
     * Run the check drafts task
     * This task checks the existence of drafts, that should be in Economic
     * This includes:
     * - Checking if the drafts exist in Economic
     * - Checking if the drafts are in the correct state (If it has been booked, it should have a booked invoice id)
     *
     * @return void
     * @throws Exception If the task fails
     */
    public function runCheckDrafts(): void
    {
        // Define the invoice object
        $collected_order_invoices_o = new collected_order_invoices_o();
        // Get the drafts
        $drafts = $collected_order_invoices_o->getTotalInvoices(
            $collected_order_invoices_o,
            [
                'booked_invoice_id' => null,
                'external_id' => 'NOT NULL',
            ],
        );
        // Check if the drafts exist in Economic
        $economic = new economic();
        // Get the economic drafts
        try {
            $economic_drafts = $economic->invoices->drafts->get([], [
                'maxPageSize' => 1000,
                'pageSize' => 1000,
                'skipPages' => 0,
            ])->collection;
        } catch (Exception $e) {
            // If the drafts do not exist, set the error
            return;
        }
        // Define the external ids
        $external_ids = [];
        // Loop through the economic drafts
        foreach ( $economic_drafts as $draft ) {
            // Get the external id
            try {
                $external_id = $draft?->references?->other ?? null;
            } catch (Exception $e) {
                // If the external id does not exist, set it to null
                $external_id = null;
            }
            // Check if the external id exists in Economic
            if (!empty($external_id)) {
                // Add the external id to the array
                $external_ids[] = $external_id;
            }
        }

        // Define the missing drafts array
        $missing_drafts = [];

        // Loop through the drafts
        foreach ( $drafts as $draft ) {
            // Check if the external id exists in the drafts
            if (!in_array($draft['external_id'], $external_ids)) {
                // If the external id does not exist, add it to the missing drafts array
                $invoice_id = $draft['id'];
                $missing_drafts[$invoice_id] = $draft['external_id'];
            } else {
                // Check if the draft has an error message, that states that the draft does not exist
                // In this case, we need to remove the error message
                if (!empty($draft['error_message'])) {
                    switch ($draft['error_message']) {
                        case ERROR_MESSAGE_ECONOMIC_INVOICE_NOT_FOUND:
                        case ERROR_MESSAGE_ECONOMIC_INVOICE_DRAFT_NOT_FOUND:
                            // If the draft does not exist, remove the error message
                            $invoice_object = (new collected_order_invoices_o())->select($draft['id']);
                            $invoice_object->error_message->nullify();
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        // Define the errors array
        $errors = [];


        // Loop through the missing drafts, and check if they are booked
        foreach ( $missing_drafts as $draft_id => $draft_external_id ) {
            // Check if the draft has been booked
            //echo 'Checking if draft ' . $draft_external_id . ' has been booked' . PHP_EOL;
            try {
                // Get the booked invoice
                $booked_invoice_id = $economic->invoices->booked->get_from_external_id($draft_external_id);
            } catch (Exception $e) {
                // If the booked invoice does not exist, set it to null
                //echo 'Was unable to find booked invoice for draft ' . $draft_external_id . PHP_EOL;
                $booked_invoice_id = null;
            }
            // Get the invoice object
            $invoice_object = (new collected_order_invoices_o())->select($draft_id);
            // Check if the booked invoice exists
            if ($booked_invoice_id !== null) {
                //echo 'FOUND BOOKED INVOICE (' . $draft_id . ') FOR DRAFT ' . $draft_external_id . PHP_EOL;
                // Check if the booked invoice id is null
                if (!empty($invoice_object->booked_invoice_id->value())) {
                    // Something went wrong, the booked invoice id is not null
                    throw new Exception('Booked invoice id is not null, but should be null, for draft ' . $draft_external_id);
                } else {
                    // If the booked invoice id is null, set it to the booked invoice id
                    $invoice_object->booked_invoice_id->set((int)$booked_invoice_id);
                    //echo 'Setting booked invoice id to ' . $booked_invoice_id . PHP_EOL;
                }
            } else {
                // If the booked invoice does not exist, set the error
                //echo 'DRAFT ' . $draft_external_id . ' HAS NOT BEEN BOOKED' . PHP_EOL;
                //echo 'Setting error message for draft ' . $draft_external_id . PHP_EOL;
                $invoice_object->error_message->set(ERROR_MESSAGE_ECONOMIC_INVOICE_NOT_FOUND);
            }
        }
    }

    /**
     * Run the check errors task
     * This task checks the invoice & invoice drafts with errors, to see if they are in the correct state
     * This includes:
     * - Checking if the invoices exist in Economic
     * - Checking if the invoices are in the correct state (If it has been sent, it should be in the sent state)
     * - Checking if the invoices are in the correct state (If it has been booked, it should have a booked invoice id)
     * @return void
     * @throws Exception If the task fails
     */
    public function runCheckErrors(): void
    {
        // Define the invoice object
        $collected_order_invoices_o = new collected_order_invoices_o();
        // Get the invoices
        $invoices = $collected_order_invoices_o->getTotalInvoices(
            $collected_order_invoices_o,
            [
                'error_message' => 'NOT NULL',
            ],
        );
        // Define the errors array
        $errors = [];
        // Loop through the drafts
        foreach ( $invoices as $invoice ) {
            // Check if the external id exists in the drafts
            if (!empty($invoice['external_id'])) {
                // Add the external id to the errors array
                $errors[$invoice['error_message']][] = $invoice;
            }
        }
        // Loop through the error messages
        foreach ( $errors as $error_message => $invoices ) {
            // Check if the error message is in the errors array
            //echo 'Checking error message: ' . $error_message . PHP_EOL;
            switch ($error_message) {
                case ERROR_MESSAGE_ECONOMIC_INVOICE_DRAFT_NOT_FOUND:
                case ERROR_MESSAGE_ECONOMIC_INVOICE_NOT_FOUND:
                    //print_r($invoices);
                    // Check if the invoices have a booked invoice id
                    foreach ( $invoices as $invoice ) {
                        $invoice_object = (new collected_order_invoices_o())->select($invoice['id']);
                        if (!empty($invoice['booked_invoice_id'])) {
                            // If the booked invoice id is not null, set the error message to null
                            $invoice_object->error_message->nullify();
                        } elseif ($invoice['booked_invoice_id'] === null) {
                            // If the booked invoice id is null, check if the invoice draft exists in Economic
                            $economic_tmp = new economic();
                            $draft_id = null;
                            try {
                                $draft_id = $economic_tmp->invoices->draft->get_from_external_id($invoice['external_id']);
                            } catch (Exception $e) {
                                // If the draft does not exist, we don't need to do anything
                            }
                            if (!empty($draft_id)) {
                                // If the draft exists, set the booked invoice id to null
                                $invoice_object->error_message->nullify();
                            }
                        } else {
                            // If the booked invoice id is null, we don't need to do anything
                            continue;
                        }
                    }
                    break;
                default:
                    throw new Exception('Unknown error message: ' . $error_message);
                    break;
            }
        }
        return;
    }
}