<?php

namespace App\Services;

use Cart\Cart;
use Cart\Currency;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;

class CartService
{
    private OcRegistryDecorator $oc;
    private Cart $cart;
    private Currency $currency;

    public function __construct(OcRegistryDecorator $registry, Cart $cart, Currency $currency)
    {
        $this->oc = $registry;
        $this->cart = $cart;
        $this->currency = $currency;
    }

    public function getCart(): array
    {
        $this->oc->load->language('checkout/cart');

        if ($this->oc->cart->hasProducts()) {
            if (
                ! $this->oc->cart->hasStock()
                && (
                    ! $this->oc->config->get('config_stock_checkout')
                    || $this->oc->config->get('config_stock_warning')
                )
            ) {
                $data['error_warning'] = $this->oc->language->get('error_stock');
            } elseif (isset($this->oc->session->data['error'])) {
                $data['error_warning'] = $this->oc->session->data['error'];

                unset($this->oc->session->data['error']);
            } else {
                $data['error_warning'] = '';
            }

            if ($this->oc->config->get('config_customer_price') && ! $this->oc->customer->isLogged()) {
                $data['attention'] = sprintf(
                    $this->oc->language->get('text_login'),
                    $this->oc->url->link('account/login'),
                    $this->oc->url->link('account/register')
                );
            } else {
                $data['attention'] = '';
            }

            if (isset($this->oc->session->data['success'])) {
                $data['success'] = $this->oc->session->data['success'];

                unset($this->oc->session->data['success']);
            } else {
                $data['success'] = '';
            }

            if ($this->oc->config->get('config_cart_weight')) {
                $data['weight'] = $this->oc->weight->format(
                    $this->oc->cart->getWeight(),
                    $this->oc->config->get('config_weight_class_id'),
                    $this->oc->language->get('decimal_point'),
                    $this->oc->language->get('thousand_point')
                );
            } else {
                $data['weight'] = '';
            }

            $this->oc->load->model('tool/image');
            $this->oc->load->model('tool/upload');

            $data['products'] = array();

            $products = $this->oc->cart->getProducts();

            foreach ($products as $product) {
                $product_total = 0;

                foreach ($products as $product_2) {
                    if ($product_2['product_id'] == $product['product_id']) {
                        $product_total += $product_2['quantity'];
                    }
                }

                if ($product['minimum'] > $product_total) {
                    $data['error_warning'] = sprintf(
                        $this->oc->language->get('error_minimum'),
                        $product['name'],
                        $product['minimum']
                    );
                }

                if ($product['image']) {
                    $image = $this->oc->model_tool_image->resize(
                        $product['image'],
                        $this->oc->config->get('theme_' . $this->oc->config->get('config_theme') . '_image_cart_width'),
                        $this->oc->config->get('theme_' . $this->oc->config->get('config_theme') . '_image_cart_height')
                    );
                } else {
                    $image = '';
                }

                $option_data = array();

                foreach ($product['option'] as $option) {
                    if ($option['type'] != 'file') {
                        $value = $option['value'];
                    } else {
                        $upload_info = $this->oc->model_tool_upload->getUploadByCode($option['value']);

                        if ($upload_info) {
                            $value = $upload_info['name'];
                        } else {
                            $value = '';
                        }
                    }

                    $option_data[] = [
                        'product_option_id' => (int) $option['product_option_id'],
                        'product_option_value_id' => (int) $option['product_option_value_id'],
                        'name' => $option['name'],
                        'value' => (strlen($value) > 20 ? substr($value, 0, 20) . '..' : $value),
                        'type' => $option['type'],
                    ];
                }

                $priceNumeric = 0;
                $totalNumeric = 0;

                // Display prices
                if ($this->oc->customer->isLogged() || ! $this->oc->config->get('config_customer_price')) {
                    $unit_price = $this->oc->tax->calculate(
                        $product['price'],
                        $product['tax_class_id'],
                        $this->oc->config->get('config_tax')
                    );

                    $priceNumeric = $unit_price;
                    $totalNumeric = $unit_price * $product['quantity'];

                    $price = $this->currency->format($unit_price, $this->oc->session->data['currency']);
                    $total = $this->currency->format($totalNumeric, $this->oc->session->data['currency']);
                } else {
                    $price = false;
                    $total = false;
                }

                $recurring = '';

                if ($product['recurring']) {
                    $frequencies = array(
                        'day' => $this->oc->language->get('text_day'),
                        'week' => $this->oc->language->get('text_week'),
                        'semi_month' => $this->oc->language->get('text_semi_month'),
                        'month' => $this->oc->language->get('text_month'),
                        'year' => $this->oc->language->get('text_year')
                    );

                    if ($product['recurring']['trial']) {
                        $recurring = sprintf(
                            $this->oc->language->get('text_trial_description'),
                            $this->currency->format(
                                $this->oc->tax->calculate(
                                    $product['recurring']['trial_price'] * $product['quantity'],
                                    $product['tax_class_id'],
                                    $this->oc->config->get('config_tax')
                                ),
                                $this->oc->session->data['currency']
                            ),
                            $product['recurring']['trial_cycle'],
                            $frequencies[$product['recurring']['trial_frequency']],
                            $product['recurring']['trial_duration']
                        ) . ' ';
                    }

                    if ($product['recurring']['duration']) {
                        $recurring .= sprintf(
                            $this->oc->language->get('text_payment_description'),
                            $this->currency->format(
                                $this->oc->tax->calculate(
                                    $product['recurring']['price'] * $product['quantity'],
                                    $product['tax_class_id'],
                                    $this->oc->config->get('config_tax')
                                ),
                                $this->oc->session->data['currency']
                            ),
                            $product['recurring']['cycle'],
                            $frequencies[$product['recurring']['frequency']],
                            $product['recurring']['duration']
                        );
                    } else {
                        $recurring .= sprintf(
                            $this->oc->language->get('text_payment_cancel'),
                            $this->currency->format(
                                $this->oc->tax->calculate(
                                    $product['recurring']['price'] * $product['quantity'],
                                    $product['tax_class_id'],
                                    $this->oc->config->get('config_tax')
                                ),
                                $this->oc->session->data['currency']
                            ),
                            $product['recurring']['cycle'],
                            $frequencies[$product['recurring']['frequency']],
                            $product['recurring']['duration']
                        );
                    }
                }

                $data['products'][] = array(
                    'product_id' => (int) $product['product_id'],
                    'cart_id' => (int) $product['cart_id'],
                    'thumb' => $image,
                    'name' => $product['name'],
                    'model' => $product['model'],
                    'option' => $option_data,
                    'recurring' => $recurring,
                    'quantity' => (int) $product['quantity'],
                    'stock' => $product['stock'] ? true : ! (! $this->oc->config->get(
                        'config_stock_checkout'
                    ) || $this->oc->config->get('config_stock_warning')),
                    'reward' => ($product['reward'] ? sprintf(
                        $this->oc->language->get('text_points'),
                        $product['reward']
                    ) : ''),
                    'price' => $price,
                    'total' => $total,
                    'href' => $this->oc->url->link('product/product', 'product_id=' . $product['product_id']),

                    'price_numeric' => $priceNumeric,
                    'total_numeric' => $totalNumeric,
                    'reward_numeric' => $product['reward'] ?? 0,
                );
            }

            // Totals
            $this->oc->load->model('setting/extension');

            $totals = array();
            $taxes = $this->oc->cart->getTaxes();
            $total = 0;

            // Because __call can not keep var references so we put them into an array.
            $total_data = array(
                'totals' => &$totals,
                'taxes' => &$taxes,
                'total' => &$total
            );

            $sort_order = array();

            $results = $this->oc->model_setting_extension->getExtensions('total');

            foreach ($results as $key => $value) {
                $sort_order[$key] = $this->oc->config->get('total_' . $value['code'] . '_sort_order');
            }

            array_multisort($sort_order, SORT_ASC, $results);

            foreach ($results as $result) {
                if ($this->oc->config->get('total_' . $result['code'] . '_status')) {
                    $this->oc->load->model('extension/total/' . $result['code']);

                    // We have to put the totals in an array so that they pass by reference.
                    $this->oc->{'model_extension_total_' . $result['code']}->getTotal($total_data);
                }
            }

            $sort_order = array();

            foreach ($totals as $key => $value) {
                $sort_order[$key] = $value['sort_order'];
            }

            array_multisort($sort_order, SORT_ASC, $totals);

            $data['totals'] = array();

            foreach ($totals as $total) {
                $data['totals'][] = [
                    'code' => $total['code'],
                    'title' => $total['title'],
                    'value' => $total['value'],
                    'sort_order' => $total['sort_order'],
                    'text' => $this->currency->format($total['value'], $this->oc->session->data['currency']),
                ];
            }

            $lastTotal = $totals[count($totals) - 1] ?? false;
            $data['total'] = $lastTotal ? $lastTotal['value'] : 0;
            $data['total_text'] = $lastTotal
                ? $this->currency->format($lastTotal['value'], $this->oc->session->data['currency'])
                : 0;
            $data['total_products_count'] = $this->oc->cart->countProducts();
        } else {
            $data['text_error'] = $this->oc->language->get('text_empty');
            $data['totals'] = [];
            $data['total'] = 0;
            $data['total_text'] = '';
            $data['products'] = [];
            $data['total_products_count'] = 0;
            unset($this->oc->session->data['success']);
        }

        return $data;
    }

    public function flush(): void
    {
        $this->cart->clear();
    }
}
