<?php

namespace Bastion\Handlers;

use App\Services\SettingsService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use Openguru\OpenCartFramework\Support\Str;

class AutocompleteHandler
{
    private OcRegistryDecorator $registry;
    private Builder $queryBuilder;
    private SettingsService $settings;

    public function __construct(
        OcRegistryDecorator $registry,
        Builder $queryBuilder,
        SettingsService $settings
    ) {
        $this->registry = $registry;
        $this->queryBuilder = $queryBuilder;
        $this->settings = $settings;
    }

    public function getCategoriesFlat(): JsonResponse
    {
        $languageId = $this->settings->config()->getApp()->getLanguageId();
        $categoriesFlat = $this->getFlatCategories($languageId);

        return new JsonResponse([
            'data' => $categoriesFlat,
        ]);
    }

    public function getCategories(): JsonResponse
    {
        $languageId = $this->settings->config()->getApp()->getLanguageId();

        $categoriesFlat = $this->getFlatCategories($languageId);

        $categories = $this->buildCategoryTree($categoriesFlat);

        return new JsonResponse([
            'data' => $categories,
        ]);
    }

    public function getProductsById(Request $request): JsonResponse
    {
        $productIds = $request->json('product_ids', []);
        $products = [];

        if ($productIds) {
            $products = array_map(function ($productId) {
                $item = [
                    'id' => (int) $productId,
                ];
                $product = $this->registry->model_catalog_product->getProduct($productId);

                $item['name'] = $product ? Str::htmlEntityEncode($product['name']) : 'No name';

                return $item;
            }, $productIds);
        }

        return new JsonResponse([
            'data' => $products,
        ]);
    }

    public function getCategoriesById(Request $request): JsonResponse
    {
        $ids = $request->json('category_ids', []);
        $items = [];

        if ($ids) {
            $items = array_map(function ($id) {
                $item = [
                    'id' => (int) $id,
                ];
                $entity = $this->registry->model_catalog_category->getCategory($id);

                $item['name'] = $entity ? Str::htmlEntityEncode($entity['name']) : 'No name';

                return $item;
            }, $ids);
        }

        return new JsonResponse([
            'data' => $items,
        ]);
    }

    private function getFlatCategories(int $languageId): array
    {
        return $this->queryBuilder->newQuery()
            ->select([
                'categories.category_id' => 'id',
                'categories.parent_id' => 'parent_id',
                'descriptions.name' => 'name',
                'descriptions.description' => 'description',
            ])
            ->from(db_table('category'), 'categories')
            ->join(
                db_table('category_description') . ' AS descriptions',
                function (JoinClause $join) use ($languageId) {
                    $join->on('categories.category_id', '=', 'descriptions.category_id')
                        ->where('descriptions.language_id', '=', $languageId);
                }
            )
            ->where('categories.status', '=', 1)
            ->orderBy('parent_id')
            ->orderBy('sort_order')
            ->get();
    }

    private function buildCategoryTree(array $flat, $parentId = 0): array
    {
        $branch = [];

        foreach ($flat as $category) {
            if ((int) $category['parent_id'] === (int) $parentId) {
                $children = $this->buildCategoryTree($flat, $category['id']);
                if ($children) {
                    $category['children'] = $children;
                }

                $branch[] = [
                    'key' => (int) $category['id'],
                    'label' => Str::htmlEntityEncode($category['name']),
                    'data' => [
                        'description' => Str::htmlEntityEncode($category['description']),
                    ],
                    'icon' => null,
                    'children' => $category['children'] ?? [],
                ];
            }
        }

        return $branch;
    }
}
