<?php

declare(strict_types=1);

namespace Banyo\CustomProduct\Model\Layer\Filter\CategoryFilter;

use Magento\Catalog\Api\Data\CategoryInterface;
use Magento\Framework\Data\Collection\AbstractDb;

class TreeBuilder extends \Mirasvit\LayeredNavigation\Model\Layer\Filter\CategoryFilter\TreeBuilder
{
    /**
     * Returns sorted and filtered category items.
     */
    public function getItems(CategoryInterface $category, array $facetData, bool $isShowNestedCategories): array
    {
        try {
            $items = $this->getDeepCategoryItems($category, $facetData);
        } catch (\Exception $e) {
            return [];
        }

        $entryLevel = $this->getEntryLevel($items);

        if ($isShowNestedCategories) {
            $items = $this->sortFilterItems($items, 0, $entryLevel);
        }

        foreach (array_keys($items) as $key) {
            $items[$key]['level'] -= $entryLevel;

            if (!$isShowNestedCategories && $items[$key]['level'] > 0) {
                unset($items[$key]);
            }
        }

        $result = [];
        foreach ($items as $item) {
            if ($item['children'] !== 0) {
                $result[] = $item;
            }
        }

        return $result;
    }

    /**
     * Builds a list of category items with hierarchical info.
     */
    public function getDeepCategoryItems(CategoryInterface $primaryCategory, array $facetData): array
    {
        $collection = $this->getDeepCategoryCollection($primaryCategory);
        $items = [];

        foreach ($collection as $category) {
            $count = $facetData[$category->getId()]['count'] ?? 0;

            $items[$category->getId()] = [
                'label'       => $category->getName(),
                'value'       => $category->getId(),
                'count'       => $count,
                'level'       => (int)$category->getLevel(),
                'category_id' => (int)$category->getId(),
                'parent_id'   => (int)$category->getParentId(),
                'parent_ids'  => (array)$category->getParentIds(),
                'children'    => $count,
                'url'         => $category->getUrl(),
            ];
        }

        foreach ($items as $item) {
            foreach ($item['parent_ids'] as $parentId) {
                if (isset($items[$parentId])) {
                    $items[$parentId]['children'] += $item['count'];
                }
            }
        }

        return array_values($items);
    }

    /**
     * Customize the collection to exclude categories.
     */
    public function getDeepCategoryCollection(CategoryInterface $parentCategory): AbstractDb
    {
        $excludedCategoryIds = [183,191];

        $collection = $parentCategory->getCollection();
        $collection->addAttributeToSelect('name');

        if ($collection instanceof \Magento\Catalog\Model\ResourceModel\Category\Flat\Collection) {
            $tableAlias = 'main_table';

            $collection
                ->addAttributeToFilter('main_table.is_active', 2)
                ->addFieldToFilter('main_table.level', ['gt' => 1])
                ->addFieldToFilter('main_table.entity_id', ['nin' => $excludedCategoryIds])
                ->setOrder('main_table.position', 'asc');
        } else {
            $tableAlias = 'e';

            $collection
                ->addAttributeToFilter('is_active', 1)
                ->addFieldToFilter('level', ['gt' => 1])
                ->addFieldToFilter('entity_id', ['nin' => $excludedCategoryIds])
                ->setOrder('position', 'asc');
        }

        $collection->getSelect()->joinLeft(
            ['parent' => $collection->getMainTable()],
            $tableAlias . '.parent_id = parent.entity_id',
            ['parent_path' => 'parent.path']
        );

        return $collection;
    }

    /**
     * Recursively sorts category items.
     */
    public function sortFilterItems(array $items, int $parentId, int $level): array
    {
        $result = [];

        foreach ($items as $item) {
            if ($item['level'] !== $level || ($item['parent_id'] != $parentId && $parentId !== 0)) {
                continue;
            }

            $childItems = array_filter($items, fn($i) => in_array($item['category_id'], $i['parent_ids']));
            $subItems = $this->sortFilterItems($childItems, $item['category_id'], $level + 1);

            if (count($subItems)) {
                $item['is_parent'] = true;
            }

            $result[] = $item;
            foreach ($subItems as $subItem) {
                $result[] = $subItem;
            }
        }

        return $result;
    }

    /**
     * Determines the minimum level among items.
     */
    public function getEntryLevel(array $items): int
    {
        $levels = array_column($items, 'level');
        return empty($levels) ? 0 : min($levels);
    }
}
