<?php

namespace statistics;

use classes\economic;
use traits\statistic_t;

class economic_s
{
    use statistic_t;

    /**
     * Get the totals for the invoices
     * WARNING: This is function does NOT support time filtering
     * @return $this
     */
    public function get_totals(): economic_s
    {
        // Get the economic class
        $economic = new economic();
        // Get the totals
        $data = $economic->invoices->totals->get();
        // Add the data
        $this->add_data_set('Drafts', [
            'netAmountInBaseCurrency' => $data->drafts->netAmountInBaseCurrency,
            'invoiceCount' => $data->drafts->invoiceCount,
        ]);
        $this->add_data_set('Booked', [
            'netAmountInBaseCurrency' => $data->booked->netAmountInBaseCurrency,
            'invoiceCount' => $data->booked->invoiceCount,
        ]);
        $this->add_data_set('Unpaid', [
            'netAmountInBaseCurrency' => $data->booked->unpaid->netAmountInBaseCurrency,
            'invoiceCount' => $data->booked->unpaid->invoiceCount,
        ]);
        $this->add_data_set('Not Overdue', [
            'netAmountInBaseCurrency' => $data->booked->unpaid->notOverdue->netAmountInBaseCurrency,
            'invoiceCount' => $data->booked->unpaid->notOverdue->invoiceCount,
        ]);
        $this->add_data_set('Overdue', [
            'netAmountInBaseCurrency' => $data->booked->unpaid->overdue->netAmountInBaseCurrency,
            'invoiceCount' => $data->booked->unpaid->overdue->invoiceCount,
        ]);
        $this->add_data_set('Paid', [
            'netAmountInBaseCurrency' => $data->booked->paid->netAmountInBaseCurrency,
            'invoiceCount' => $data->booked->paid->invoiceCount,
        ]);
        return $this;
    }

    /**
     * Get department sent invoice total amount and count
     * @return $this
     */
    public function get_department_sent_invoice_totals(): economic_s
    {
        // Get the economic class
        $economic = new economic();

        // Get the totals
        $invoices = $economic->invoices->booked->get([
            '(date$gte:' . $this->start . '$and:date$lte:' . $this->end . ')' => '', // To allow for time filtering, we need to add the time frame to the query
        ])->collection;

        // Get the departments
        $departments = $economic->departments->departments->get(
            [],
            [
                'skipPages' => 0,
                'pageSize' => 1000, // Since the limit is 1000, we need to set the page size to 1000.
            ]
        )->collection;
        /**
         * To get the department name from the department number, we need to create an array with the department number as the key and the department name as the value.
         * This results in an array like this:
         * departmentNumber => name
         * [
         *   10 => ['name' => 'Department 1', 'departmentNumber' => 10, 'products' => ['product 1' => 10, 'product 2' => 20], 'totalNetAmount' => 0],
         *   20 => ['name' => 'Department 2', 'departmentNumber' => 20, 'products' => ['product 1' => 10, 'product 2' => 20], 'totalNetAmount' => 0],
         * ]
         */
        $departments_temp = array_column($departments, 'name', 'departmentNumber');
        // Add an unknown (0) department, in case the departmentDistributionNumber is not set
        $departments_temp[0] = 'Unknown';
        $departments = [];
        foreach ( $departments_temp as $departmentNumber => $name ) {
            $departments[$departmentNumber] = [
                'name' => $name,
                'departmentNumber' => $departmentNumber,
                'products' => [],
                'totalNetAmount' => 0,
                'invoiceCount' => 0,
            ];
        }

        // Get the bookedInvoiceNumbers
        $booked_invoice_numbers = [];
        foreach ( $invoices as $invoice ) {
            $booked_invoice_numbers[] = $invoice->bookedInvoiceNumber;
        }
        // Get the invoice lines
        $invoice_lines = $economic->invoices->booked->get_invoice_lines($booked_invoice_numbers);

        // Clear the invoice lines that has quantity 0, since they don't have any value to the statistics
        foreach ( $invoice_lines as $invoice_id => $lines ) {
            foreach ( $lines as $key => $line ) {
                if ($line->quantity == 0) {
                    unset($invoice_lines[$invoice_id][$key]);
                }
            }
        }

        // Add the net amount, invoice count and products array to the departments
        foreach ( $invoice_lines as $invoice_id => $lines ) {
            foreach ( $lines as $line ) {
                // Check if the departmentDistributionNumber is set and the quantity is greater than 0
                $tmp_department = 0;
                if (isset($line->departmentalDistribution->departmentalDistributionNumber)) {
                    // Set the department to unknown
                    $tmp_department = $line->departmentalDistribution->departmentalDistributionNumber;
                }
                if ($line->quantity == 0) {
                    // Skip the line if the quantity is 0
                    continue;
                }
                // Add the net amount to the department
                $departments[$tmp_department]['totalNetAmount'] += $line->totalNetAmount;
                // Add the product to the department
                if (!isset($departments[$tmp_department]['products'][$line->product->productNumber])) {
                    $departments[$tmp_department]['products'][$line->product->productNumber] = 0;
                }
                $departments[$tmp_department]['products'][$line->product->productNumber] += $line->quantity;
                // Add the invoice count to the department
                $departments[$tmp_department]['invoiceCount']++;
            }
        }

        // Add the data sets
        foreach ( $departments as $department ) {
            $this->add_data_set($department['name'], [
                'Faktureret (DKK)' => $department['totalNetAmount'],
            ]);
            $this->set_raw_data($department['departmentNumber'], [
                'invoiceCount' => $department['invoiceCount'],
                'products' => $department['products'],
                'totalNetAmount' => $department['totalNetAmount'],
                'name' => $department['name'],
            ]);
        }

        return $this;
    }

    /**
     * Get department draft invoice total amount and count
     * @return $this
     */
    public function get_department_draft_invoice_totals(): economic_s
    {
        // Get the economic class
        $economic = new economic();

        // Get the totals
        $invoices = $economic->invoices->drafts->get([
            '(date$gte:' . $this->start . '$and:date$lte:' . $this->end . ')' => '', // To allow for time filtering, we need to add the time frame to the query
        ])->collection;

        // Get the departments
        $departments = $economic->departments->departments->get(
            [],
            [
                'skipPages' => 0,
                'pageSize' => 1000, // Since the limit is 1000, we need to set the page size to 1000.
            ]
        )->collection;
        /**
         * To get the department name from the department number, we need to create an array with the department number as the key and the department name as the value.
         * This results in an array like this:
         * departmentNumber => name
         * [
         *   10 => ['name' => 'Department 1', 'departmentNumber' => 10, 'products' => ['product 1' => 10, 'product 2' => 20], 'totalNetAmount' => 0],
         *   20 => ['name' => 'Department 2', 'departmentNumber' => 20, 'products' => ['product 1' => 10, 'product 2' => 20], 'totalNetAmount' => 0],
         * ]
         */
        $departments_temp = array_column($departments, 'name', 'departmentNumber');
        // Add an unknown (0) department, in case the departmentDistributionNumber is not set
        $departments_temp[0] = 'Unknown';
        $departments = [];
        foreach ( $departments_temp as $departmentNumber => $name ) {
            $departments[$departmentNumber] = [
                'name' => $name,
                'departmentNumber' => $departmentNumber,
                'products' => [],
                'totalNetAmount' => 0,
                'invoiceCount' => 0,
            ];
        }

        // Get the draftInvoiceNumber for the draft invoices
        $draft_invoice_number = [];
        foreach ( $invoices as $invoice ) {
            $draft_invoice_number[] = $invoice->draftInvoiceNumber;
        }
        // Get the invoice lines
        $invoice_lines = $economic->invoices->drafts->get_invoice_lines($draft_invoice_number);

        // Clear the invoice lines that has quantity 0, since they don't have any value to the statistics
        foreach ( $invoice_lines as $invoice_id => $lines ) {
            foreach ( $lines as $key => $line ) {
                // If the quantity key does not exist, we can just set the quantity to 0
                if (!isset($line->quantity)) {
                    $line->quantity = 0;
                }
                // If the quantity is 0, we can unset the line, since it does not have any value to the statistics
                if ($line->quantity == 0) {
                    unset($invoice_lines[$invoice_id][$key]);
                }
            }
        }

        // Add the net amount, invoice count and products array to the departments
        foreach ( $invoice_lines as $invoice_id => $lines ) {
            foreach ( $lines as $line ) {
                // Check if the departmentDistributionNumber is set and the quantity is greater than 0
                $tmp_department = 0;
                if (isset($line->departmentalDistribution->departmentalDistributionNumber)) {
                    // Set the department to unknown
                    $tmp_department = $line->departmentalDistribution->departmentalDistributionNumber;
                }
                if ($line->quantity == 0) {
                    // Skip the line if the quantity is 0
                    continue;
                }
                // Add the net amount to the department
                $departments[$tmp_department]['totalNetAmount'] += $line->totalNetAmount;
                // Add the product to the department
                if (!isset($departments[$tmp_department]['products'][$line->product->productNumber])) {
                    $departments[$tmp_department]['products'][$line->product->productNumber] = 0;
                }
                $departments[$tmp_department]['products'][$line->product->productNumber] += $line->quantity;
                // Add the invoice count to the department
                $departments[$tmp_department]['invoiceCount']++;
            }
        }

        // Add the data sets
        foreach ( $departments as $department ) {
            $this->add_data_set($department['name'], [
                'Faktureret (DKK)' => $department['totalNetAmount'],
            ]);
            $this->set_raw_data($department['departmentNumber'], [
                'invoiceCount' => $department['invoiceCount'],
                'products' => $department['products'],
                'totalNetAmount' => $department['totalNetAmount'],
                'name' => $department['name'],
            ]);
        }

        return $this;
    }

    /**
     * Get the total invoiced amount today
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_today(): array
    {
        return self::get_totals_in_time_frame(date('Y-m-d'), date('Y-m-d'));
    }

    /**
     * Get the total invoiced amount today
     * @return array ['drafts' => object, 'booked' => object]
     */
    protected function get_totals_in_time_frame(string $start = null, string $end = null): array
    {
        // Set the date range to the current day, if no start and end date is set
        $start = $start ?? date('Y-m-d');
        $end = $end ?? date('Y-m-d');

        // Get the economic class
        $economic = new economic();
        $repeat['drafts'] = [
            'invoiceCount' => 0,
            'repeat' => true,
            'pageCount' => 0,
        ];
        $drafts = [];
        while ($repeat['drafts']['repeat']) {
            $repeat['drafts']['repeat'] = false;
            // Merge the draft collection, since the limit is 1000, we need to get all the drafts
            $drafts_tmp = $economic->invoices->drafts->get([
                '(date$gte:' . $start . '$and:date$lte:' . $end . ')' => '', // To allow for time filtering, we need to add the time frame to the query
            ],
                [
                    'skipPages' => $repeat['drafts']['pageCount'],
                    'pageSize' => 1000, // Since the limit is 1000, we need to set the page size to 1000.
                ]
            )->collection;
            $drafts = array_merge($drafts, $drafts_tmp);

            // If the count of the drafts is equal to the limit, we need to repeat the process
            if (count($drafts_tmp) == 1000) {
                $repeat['drafts']['repeat'] = true;
                $repeat['drafts']['pageCount']++;
            }
        }
        $repeat['booked'] = [
            'invoiceCount' => 0,
            'repeat' => true,
            'pageCount' => 0,
        ];
        $booked = [];
        while ($repeat['booked']['repeat']) {
            $repeat['booked']['repeat'] = false;
            // Merge the booked collection, since the limit is 1000, we need to get all the booked
            $booked_tmp = $economic->invoices->booked->get([
                '(date$gte:' . $start . '$and:date$lte:' . $end . ')' => '', // To allow for time filtering, we need to add the time frame to the query
            ],
                [
                    'skipPages' => $repeat['booked']['invoiceCount'],
                    'pageSize' => 1000, // Since the limit is 1000, we need to set the page size to 1000.
                ]
            )->collection;
            $booked = array_merge($booked, $booked_tmp);

            // If the count of the booked is equal to the limit, we need to repeat the process
            if (count($booked_tmp) == 1000) {
                $repeat['booked']['repeat'] = true;
                $repeat['booked']['pageCount']++;
            }
        }
        $drafts_total = 0;
        $booked_total = 0;

        foreach ( $drafts as $draft_obj ) {
            $drafts_total += $draft_obj->netAmountInBaseCurrency;
        }

        foreach ( $booked as $booked_obj ) {
            $booked_total += $booked_obj->netAmountInBaseCurrency;
        }

        return [
            'drafts' => [
                'netAmountInBaseCurrency' => $drafts_total,
                'invoiceCount' => count($drafts),
            ],
            'booked' => [
                'netAmountInBaseCurrency' => $booked_total,
                'invoiceCount' => count($booked),
            ],
            'total' => $drafts_total + $booked_total,
            'start' => $start,
            'end' => $end,
        ];
    }

    /**
     * Get the total invoiced amount this week
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_this_week(): array
    {
        return self::get_totals_in_time_frame(date('Y-m-d', strtotime('monday this week')), date('Y-m-d'));
    }

    /**
     * Get the total invoiced amount this month 1st to last day of the month
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_this_month(): array
    {
        return self::get_totals_in_time_frame(date('Y-m-01'), date('Y-m-t'));
    }


    /**
     * Get the total invoiced amount last month 1st to last day of the month
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_last_month(): array
    {
        return self::get_totals_in_time_frame(date('Y-m-01', strtotime('last month')), date('Y-m-t', strtotime('last month')));
    }

    /**
     * Get the total invoiced amount last year
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_last_year(): array
    {
        return self::get_totals_in_time_frame(date('Y-01-01', strtotime('last year')), date('Y-12-31', strtotime('last year')));
    }

    /**
     * Get the total invoiced amount yesterday
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_yesterday(): array
    {
        return self::get_totals_in_time_frame(date('Y-m-d', strtotime('yesterday')), date('Y-m-d', strtotime('yesterday')));
    }

    /**
     * Get the total invoiced amount this year
     * @return array ['drafts' => object, 'booked' => object]
     */
    public function get_totals_this_year(): array
    {
        return self::get_totals_in_time_frame(date('Y-01-01'), date('Y-12-31'));
    }

    public function get_totals_departments()
    {
        // Get the
    }

}