<?php
/*
 *   $Id$
 *
 *   AbanteCart, Ideal OpenSource Ecommerce Solution
 *   http://www.AbanteCart.com
 *
 *   Copyright © 2011-2025 Belavier Commerce LLC
 *
 *   This source file is subject to Open Software License (OSL 3.0)
 *   License details are bundled with this package in the file LICENSE.txt.
 *   It is also available at this URL:
 *   <http://www.opensource.org/licenses/OSL-3.0>
 *
 *  UPGRADE NOTE:
 *    Do not edit or add to this file if you wish to upgrade AbanteCart to newer
 *    versions in the future. If you wish to customize AbanteCart for your
 *    needs, please refer to http://www.AbanteCart.com for more information.
 */

/** @noinspection PhpMultipleClassDeclarationsInspection */
class ControllerPagesProductCategory extends AController
{
    public function __construct(Registry $registry, $instance_id, $controller, $parent_controller = '')
    {
        parent::__construct($registry, $instance_id, $controller, $parent_controller);
        $this->prepareProductListingParameters();
        $this->data['thumb_no_image'] = [
            'category' => true,
            'product'  => true,
        ];
    }

    public function main()
    {
        $request = $this->request->get;

        $this->data['cart_rt'] = $this->config->get('embed_mode')
            ? 'r/checkout/cart/embed'
            : 'checkout/cart';

        //init controller data
        $this->extensions->hk_InitData($this, __FUNCTION__);

        $this->loadLanguage('product/category');
        $this->document->resetBreadcrumbs();
        $this->document->addBreadcrumb(
            [
                'href'      => $this->html->getHomeURL(),
                'text'      => $this->language->get('text_home'),
                'separator' => false,
            ]
        );

        $category_info = [];
        $httpQuery = $this->prepareProductSortingParameters();
        extract($httpQuery);
        unset($httpQuery['raw_sort']);

        $brands = $request['manufacturer_id'];
        if ($brands && is_array($brands)) {
            $httpQuery['manufacturer_id'] = $brands;
        }
        $ratings = $request['rating'];
        if ($ratings && is_array($ratings)) {
            $httpQuery['rating'] = $ratings;
        }

        $httpQuery = array_merge($httpQuery, (array) $this->data['additional_filters']);

        /** @var ModelCatalogCategory $mdl */
        $mdl = $this->loadModel('catalog/category');
        $this->loadModel('tool/seo_url');
        if (!isset($request['path']) && isset($request['category_id']) && is_numeric($request['category_id'])) {
            $request['path'] = $request['category_id'];
        }

        if ($request['path']) {
            $httpQuery['path'] = $this->data['path'] = $request['path'];
            $path = '';
            $parts = explode('_', $request['path']);
            if (count($parts) == 1) {
                //if this is a category ID to subcategory, need to build a full path
                $parts = explode('_', $mdl->buildPath($request['path']));
            }
            $currentId = end($parts);
            $category_id = [$currentId];
            foreach ($parts as $path_id) {
                $category_info = $mdl->getCategory($path_id);
                if ($category_info) {
                    if (!$path) {
                        $path = $path_id;
                    } else {
                        $path .= '_' . $path_id;
                    }
                }
                // include subdirectories into result product list
                if ($path_id == $currentId) {
                    $category_id = array_merge($category_id, $mdl->getChildrenIDs((int) $path_id));
                }
                $this->document->addBreadcrumb(
                    [
                        'href'      => $this->html->getSEOURL('product/category', '&path=' . $path, '&encode'),
                        'text'      => $category_info['name'],
                        'separator' => $this->language->get('text_separator'),
                    ]
                );
            }

            $category_info = $mdl->getCategory(end($parts));
        } elseif (is_array($request['category_id'])) {
            $category_id = filterIntegerIdList($request['category_id']);
            if ($category_id) {
                $httpQuery['category_id'] = $category_id;
            }
            if ($category_id) {
                $extractFields = ['name', 'meta_keywords', 'meta_description', 'description'];
                $tmp = [];
                foreach ($category_id as $catId) {
                    $info = $mdl->getCategory($catId);
                    foreach ($extractFields as $fName) {
                        $tmp[$fName][] = $info[$fName];
                    }
                }
                foreach ($extractFields as $fName) {
                    $tmp[$fName] = array_unique(array_filter(array_map('trim', $tmp[$fName])));
                    $category_info[$fName] = implode(', ', $tmp[$fName]);
                }
                unset($tmp);

                if (count($category_id) == 1) {
                    $request['path'] = $mdl->buildPath(current($category_id));
                }

                $this->document->addBreadcrumb(
                    [
                        'href'      => $this->html->getSEOURL(
                            'product/category',
                            '&' . http_build_query($httpQuery)
                        ),
                        'text'      => mb_strlen($category_info['name'], 'UTF-8') > 150
                            ? mb_substr($category_info['name'], 0, 150, 'UTF-8') . '...'
                            : $category_info['name'],
                        'separator' => $this->language->get('text_separator'),
                    ]
                );
                $this->data['filter_url'] =
                    $this->html->getSEOURL('product/category', '&' . http_build_query($httpQuery));
            } else {
                $category_id = [0];
                $category_info['category_id'] = 0;
            }
        } else {
            $category_id = [0];
            $category_info['category_id'] = 0;
        }

        //if a category isn't set but brands are selected
        if (!$category_id && $httpQuery['manufacturer_id']) {
            redirect($this->html->getSecureURL('product/manufacturer', '&' . http_build_query($httpQuery)));
        }

        if ($category_info) {
            if ($this->config->get('embed_mode')) {
                $category_info['name'] = $this->language->get('text_top_category');
            }
            $this->document->setTitle($category_info['name']);
            $this->document->setKeywords($category_info['meta_keywords']);
            $this->document->setDescription($category_info['meta_description']);

            $this->data['heading_title'] = $category_info['name'];
            if (!is_array($request['category_id']) || count($request['category_id']) == 1) {
                $this->data['description'] = html_entity_decode($category_info['description'], ENT_QUOTES, 'UTF-8');
            }
            $this->data['text_sort'] = $this->language->get('text_sort');

            /** @var ModelCatalogProduct $pMdl */
            $pMdl = $this->loadModel('catalog/product');
            $category_total = isset($category_info['category_id'])
                ? $mdl->getTotalCategoriesByCategoryId($category_info['category_id'])
                : 0;

            $productFilter = [
                'sort'   => $sort,
                'order'  => $order,
                'limit'  => $limit,
                'start'  => ($page - 1) * $limit,
                'filter' => [],
            ];

            if (isset($this->request->get['manufacturer_id'])) {
                $productFilter['filter']['manufacturer_id'] = $this->request->get['manufacturer_id'];
            }
            if (isset($this->request->get['rating'])) {
                $productFilter['filter']['rating'] = $this->request->get['rating'];
            }

            $productFilter['filter'] = array_merge(
                $productFilter['filter'],
                (array) $this->data['additional_filters']
            );

            $products_result = $pMdl->getProductsByCategoryId(
                $category_id,
                $productFilter
            );
            $product_total = $products_result[0]['total_num_rows'];

            //if the requested page does not exist
            if ($product_total < ($page - 1) * $limit && $page > 1) {
                $httpQuery['page'] = 1;
                redirect($this->html->getSEOURL('product/category', '&' . http_build_query($httpQuery)));
            }

            if ($category_total || $product_total) {
                $categories = [];
                $resource = new AResource('image');

                if ($category_info['category_id']) {
                    $results = $mdl->getCategories($category_info['category_id']);
                    $category_ids = array_column($results, 'category_id');
                    //get thumbnails by one pass
                    $thumbnails = $category_ids
                        ? $resource->getMainThumbList(
                            'categories',
                            $category_ids,
                            $this->config->get('config_image_category_width'),
                            $this->config->get('config_image_category_height'),
                            $this->data['thumb_no_image']['category']
                        )
                        : [];

                    foreach ($results as $result) {
                        $thumbnail = $thumbnails[$result['category_id']];
                        $categories[] = [
                            'name'  => $result['name'],
                            'href'  => $this->html->getSEOURL(
                                'product/category',
                                '&path=' . $request['path'] . '_' . $result['category_id'],
                                '&encode'
                            ),
                            'thumb' => $thumbnail,
                        ];
                    }
                    $this->data['categories'] = $categories;
                }
                $this->data['button_add_to_cart'] = $this->language->get('button_add_to_cart');

                $product_ids = array_column($products_result, 'product_id');
                $products = [];

                $products_info = $pMdl->getProductsAllInfo($product_ids);
                $thumbnails = $product_ids
                    ? $resource->getMainThumbList(
                        'products',
                        $product_ids,
                        $this->config->get('config_image_product_width'),
                        $this->config->get('config_image_product_height'),
                        $this->data['thumb_no_image']['product']
                    )
                    : [];
                $stock_info = $pMdl->getProductsStockInfo($product_ids);
                foreach ($products_result as $result) {
                    $productId = $result['product_id'];
                    $thumbnail = $thumbnails[$productId];
                    $rating = $products_info[$productId]['rating'];
                    $special = $specialNum = false;
                    $discount = $products_info[$productId]['discount'];

                    if ($discount) {
                        $priceNum = $discount;
                    } else {
                        $priceNum = $result['price'];
                        $special = $products_info[$productId]['special'];
                        if ($special) {
                            $specialNum = $this->tax->calculate(
                                $special,
                                $result['tax_class_id'],
                                $this->config->get('config_tax')
                            );
                            $special = $this->currency->format($specialNum);
                        }
                    }
                    $priceNum =
                        $this->tax->calculate($priceNum, $result['tax_class_id'], $this->config->get('config_tax'));
                    $price = $this->currency->format($priceNum);

                    if ($products_info[$productId]['options']) {
                        $add = $this->html->getSEOURL(
                            'product/product',
                            '&product_id=' . $productId,
                            '&encode'
                        );
                    } else {
                        $add = $this->config->get('config_cart_ajax')
                            ? '#'
                            : $this->html->getSecureURL(
                                $this->data['cart_rt'],
                                '&product_id=' . $productId,
                                '&encode'
                            );
                    }
                    //check for stock status, availability and config
                    $track_stock = false;
                    $in_stock = false;
                    $no_stock_text = $this->language->get('text_out_of_stock');
                    $total_quantity = 0;
                    $stock_checkout = $result['stock_checkout'] === ''
                        ? $this->config->get('config_stock_checkout')
                        : $result['stock_checkout'];
                    if ($stock_info[$productId]['subtract']) {
                        $track_stock = true;
                        $total_quantity = $pMdl->hasAnyStock($productId);
                        //we have stock or out-of-stock checkout is allowed
                        if ($total_quantity > 0 || $stock_checkout) {
                            $in_stock = true;
                        }
                    }

                    $productHttpQuery = [];
                    if ($request['path']) {
                        $productHttpQuery['path'] = $request['path'];
                    }
                    $productHttpQuery['product_id'] = $productId;

                    $products[] = array_merge(
                        $result,
                        [
                            'product_id'     => $productId,
                            'name'           => $result['name'],
                            'blurb'          => $result['blurb'],
                            'model'          => $result['model'],
                            'rating'         => $rating,
                            'stars'          => $this->language->getAndReplace('text_stars', replaces: $rating),
                            'thumb'          => $thumbnail,
                            'price'          => $price,
                            //todo: remove in the future as deprecated
                            'raw_price'      => $priceNum,
                            'price_num'      => $priceNum,
                            'call_to_order'  => $result['call_to_order'],
                            'options'        => $products_info[$productId]['options'],
                            'special'        => $special,
                            'special_num'    => $specialNum,
                            'href'           => $this->html->getSEOURL(
                                'product/product',
                                '&' . http_build_query($productHttpQuery),
                                true
                            ),
                            'add'            => $add,
                            'description'    => html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8'),
                            'track_stock'    => $track_stock,
                            'in_stock'       => $in_stock,
                            'no_stock_text'  => $no_stock_text,
                            'total_quantity' => $total_quantity,
                            'tax_class_id'   => $result['tax_class_id'],
                        ]
                    );
                }
                $this->data['products'] = $products;

                if ($this->config->get('config_customer_price')) {
                    $display_price = true;
                } elseif ($this->customer->isLogged()) {
                    $display_price = true;
                } else {
                    $display_price = false;
                }
                $this->data['display_price'] = $display_price;

                $sort_options = $this->data['sorts'];
                $sorting = $this->html->buildElement(
                    [
                        'type'    => 'selectbox',
                        'name'    => 'sort',
                        'options' => $sort_options,
                        'value'   => $raw_sort . '-' . $order,
                    ]
                );
                $this->data['sorting'] = $sorting;
                $pQuery = $httpQuery;
                $pQuery['sort'] = $raw_sort . '-' . $pQuery['order'];
                unset($pQuery['page'], $pQuery['order']);
                $pagination_url = $this->html->getSEOURL(
                    'product/category',
                    '&page=--page--&' . http_build_query($pQuery),
                );

                $rQuery = $httpQuery;
                unset($rQuery['sort']);
                $this->data['resort_url'] = $this->html->getSecureSEOURL(
                    'product/category',
                    '&' . http_build_query($rQuery)
                );

                $this->data['pagination_bootstrap'] = $this->html->buildElement(
                    [
                        'type'       => 'Pagination',
                        'name'       => 'pagination',
                        'text'       => $this->language->get('text_pagination'),
                        'text_limit' => $this->language->get('text_per_page'),
                        'total'      => $product_total,
                        'page'       => $page,
                        'limit'      => $limit,
                        'url'        => $pagination_url,
                        'style'      => 'pagination',
                    ]
                );

                $this->data['sort'] = $sort;
                $this->data['order'] = $order;
                $this->view->setTemplate('pages/product/category.tpl');
            } else {
                $this->document->setTitle($category_info['name']);
                $this->document->setDescription($category_info['meta_description']);
                $this->data['heading_title'] = $category_info['name'];
                $this->data['text_error'] = $this->language->get('text_empty');
                $this->data['button_continue'] = $this->language->get('button_continue');
                $this->data['continue'] = $this->html->getHomeURL();
                $this->data['categories'] = [];
                $this->data['products'] = [];
                $this->view->setTemplate('pages/product/category.tpl');
            }
            $this->data['review_status'] = $this->config->get('display_reviews');
        } else {
            if (isset($request['path'])) {
                $this->document->addBreadcrumb(
                    [
                        'href'      => $this->html->getSEOURL(
                            'product/category',
                            '&path=' . $request['path'] . http_build_query($httpQuery),
                            '&encode'
                        ),
                        'text'      => $this->language->get('text_error'),
                        'separator' => $this->language->get('text_separator'),
                    ]
                );
            }

            $this->document->setTitle($this->language->get('text_error'));
            $this->data['heading_title'] = $this->language->get('text_error');
            $this->data['text_error'] = $this->language->get('text_error');
            $this->data['button_continue'] = $this->html->buildElement(
                [
                    'type'  => 'button',
                    'name'  => 'continue_button',
                    'text'  => $this->language->get('button_continue'),
                    'style' => 'button',
                ]
            );
            $this->data['continue'] = $this->html->getHomeURL();
            $this->view->setTemplate('pages/error/not_found.tpl');
        }
        $this->view->batchAssign($this->data);
        $this->processTemplate();

        //init controller data
        $this->extensions->hk_UpdateData($this, __FUNCTION__);
    }
}
