<?php

namespace Shop\Presentation\Modules\AdminProducts;

use ActiveTable\ColumnTable;
use ActiveTable\DataTableEngine;
use Core\Form\Control\Switchery;
use Core\Form\ControlBuilder;
use Core\Form\FormBuilder;
use Core\Form\NiftyControlBuilder;
use Core\Helpers\Text;
use Core\ModuleController;
use DiamondTable\CommandFactory;
use Shop\Application\Catalog\CatalogService;
use Shop\Presentation\Config\Main;
use Diamond\Helpers\Form;
use Diamond\Helpers\Formatter;
use DiamondTable\TableFactory;
use Shop\Domain\Product\Contracts\ProductEntityInterface;
use Shop\Infrastructure\Models\Product\Product;
use Shop\Presentation\Modules\AdminClients\MergerOrdersCommand;
use Shop\Presentation\Modules\AdminProducts\MergerProductsCommand;
use Shop\Infrastructure\Repositories\Brand\BrandCriteria;
use Shop\Infrastructure\Repositories\Brand\BrandRepository;
use Shop\Infrastructure\Repositories\Product\ProductCriteria;
use Shop\Infrastructure\Repositories\Product\ProductRepository;
use Shop\Infrastructure\Repositories\ProductCategory\ProductCategoryCriteria;
use Shop\Infrastructure\Repositories\ProductCategory\ProductCategoryRepository;
use Shop\Infrastructure\Repositories\ProductGroup\ProductGroupCriteria;
use Shop\Infrastructure\Repositories\ProductGroup\ProductGroupRepository;

use Shop\Presentation\UseCases\Imaging\Imaging;
use spaceonfire\CommandBus\CommandBus;

/**
 * Description of AdminProducts
 *
 * @author Dmitriy
 */
class AdminProducts extends ModuleController
{
    use FormTrait;

    protected $tableFactory;
    protected $productCategoryRepository;
    protected $brandRepository;
    protected $mainConfig;
    protected $catalogService;
    protected $productGroupRepository;


    public static array $images = [];

    protected $commandBus;

    /**
     * AdminProducts constructor.
     * @param ProductRepository $productRepository
     * @param ControlBuilder $controlBuilder
     * @param TableFactory $tableFactory
     * @param ProductCategoryRepository $productCategoryRepository
     * @param BrandRepository $brandRepository
     * @param Main $mainConfig
     * @param CatalogService $catalogService
     * @param FormBuilder $formBuilder
     * @param ProductGroupRepository $productGroupRepository
     * @param CommandBus $commandBus
     */
    public function __construct(ProductRepository         $productRepository,
                                NiftyControlBuilder       $controlBuilder,
                                TableFactory              $tableFactory,
                                ProductCategoryRepository $productCategoryRepository,
                                BrandRepository           $brandRepository,
                                Main                      $mainConfig,
                                CatalogService            $catalogService,
                                FormBuilder               $formBuilder,
                                ProductGroupRepository    $productGroupRepository,
                                CommandBus                $commandBus)
    {
        $this->productRepository = $productRepository;
        $this->tableFactory = $tableFactory;
        $this->controlBuilder = $controlBuilder;
        $this->productCategoryRepository = $productCategoryRepository;
        $this->brandRepository = $brandRepository;
        $this->mainConfig = $mainConfig;
        $this->catalogService = $catalogService;
        $this->formBuilder = $formBuilder;
        $this->productGroupRepository = $productGroupRepository;

        $this->commandBus = $commandBus;

        self::$images = Product::$images;
    }


    /**
     * @return string
     * @throws \ReflectionException
     * @throws \Repo\Concrete\Exceptions\Collection
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    public function process(): string
    {

        $table = $this->tableFactory->buildAdminTable($this->productRepository, ProductCriteria::create());

        $categories = $this->productCategoryRepository->findByCriteria(
            ProductCategoryCriteria::create()->setSortByTitle('ASC')
        );

        $categoriesAr = Form::prepareDropdown($categories, 'Раздел каталога', 'getDropdownListWithParent');

        $brands = $this->brandRepository->findByCriteria(
            BrandCriteria::create()
        );

        $brandsAr = Form::prepareDropdown($brands);

        //$groups
        $groups = $this->productGroupRepository->findByCriteria(
            ProductGroupCriteria::create()
        );
        $groupsAr = $groups->getDropDownList();

        $productGroupsIds = [];
        /**
         * @var Product $product
         */
        if (input_get('id')) {
            $product = $this->productRepository->findById(input_get('id'));

            if ($product && $product->getProductGroups()) {
                $productGroupsIds = array_keys($product->getProductGroups()->toKeyIndex());
            }
        }

        $photoControl = $this->controlBuilder->buildImgUpload('photo', $this->catalogService->getProductsImageDir(), true);

        $table->getCommandFactory()->addCommand(CommandFactory::FORM_SAVE, new SaveProductCommand($table));

        $table
            ->addRowActionCommand(
                'change-category',
                new ChangeCategoryCommand($table, $this->buildMoveCategoryForm($categoriesAr)),
                'Изменить радел каталога'
            )
            ->addRowActionCommand(
                'change-brand',
                new ChangeBrandCommand($table, $this->buildMoveBrandForm($brandsAr)),
                'Изменить производителя'
            )
            ->addRowActionCommand(
                'change-weight',
                new ChangeWeightCommand($table, $this->buildChangeWeightForm()),
                'Изменить вес'
            )
            ->addRowActionCommand(
                'change-phote',
                new ChangePhotoCommand($table, $this->buildMovePhotoForm($photoControl), $photoControl),
                'Изменить фото'
            )
            ->addRowActionCommand(
                'merge-products',
                new MergerProductsCommand($table, $this->buildMergerProductsForm(), $this->commandBus),
                'Объеденить товары'
            );

        $helpDate = '<a data-html="true" data-container="body" data-original-title="<p>Можно использвать фильтрацию<br/><=20-01-2004 (меньше либо равно)<br/>>20-01-2004(больше)</p>" href="javascript:;" class="demo-psi-information add-tooltip"></a>';

        $table
            ->setDefaultSortColumn('id', 'desc')
            ->addColumn(
                (new ColumnTable('id', '№'))
                    ->setWidth(60)
            )
            ->addColumn(
                (new ColumnTable('article', 'Артикул'))
                    ->setFormat($this, 'formatArticle')
            )
            ->addColumn(
                (new ColumnTable('title', 'Наименование'))

            )
            ->addColumn(
                (new ColumnTable('dateCreate', 'Создан '.$helpDate))->setSorted(true)->setFormat($this, 'formatDateCreate')
            )
            ->addColumn(
                (new ColumnTable('dateUpdate', 'Измененён '.$helpDate))->setSorted(true)->setFormat($this, 'formatDateUpdate')
            )
            ->addColumn(
                (new ColumnTable('price', 'Цена'))

            )
            ->addColumn(
                (new ColumnTable('pricePositions', 'Позиций'))
                    ->setFormat($this, 'formatPosCount')

            )
            ->addColumn(
                (new ColumnTable('categoryId', 'Раздел'))
                    ->setFormat($this, 'formatCategory')

            )
            ->addColumn(
                (new ColumnTable('brand', 'Производитель'))
                    ->setFormat($this, 'formatBrand')

            )
            ->addColumn(
                (new ColumnTable('groups', 'Группы'))
                    ->setFormat($this, 'formatGroups')

            )
            ->addColumn(
                (new ColumnTable('imageexist', 'Изображения'))
                    ->setFormat($this, 'formatImage')

            )
            ->addColumn(
                (new ColumnTable('special', 'Спец. предложение'))
                    ->setFormat($this, 'formatSpecial')

            )
            ->addColumn(
                (new ColumnTable('active', 'Активен'))
                    ->setFormat($this, 'formatActive')

            )
            ->addColumn(
                (new ColumnTable('actions', ''))
                    ->setFormat($this->tableFactory, 'formatActions')
            );


        $table
            ->addFilter(
                $this->controlBuilder->buildInput('filter_by_id')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_article')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_dateCreate')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_dateUpdate')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_title')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_price')
            )
            ->addFilter(
                $this->controlBuilder->buildInput('search_by_brand')
            )
            ->addFilter(
                $this->controlBuilder->buildInputSmall('filter_by_weight')
            )
            ->addFilter(
                $this->controlBuilder->buildDropdownUniform('filter_by_categoryId',
                    $categoriesAr
                )
            )
            ->addFilter(
                $this->controlBuilder->buildDropdownYNUniform('filter_by_active', [
                    null => 'любой'
                ])
            )
            ->addFilter(
                $this->controlBuilder->buildDropdownYNUniform('filter_by_special', [
                    null => 'любой'
                ])
            )
            ->addFilter(
                $this->controlBuilder->buildDropdownYNUniform('filter_by_imageexist', [
                    null => 'Любой',
                    'Y' => 'Есть'
                ])
            );

        $this->buildForm($table, $categoriesAr, $brandsAr, $groupsAr, $productGroupsIds);

        return $table->render();
    }

    /**
     * @param ProductEntityInterface|Product $product
     * @return string
     */
    public function formatDateCreate(ProductEntityInterface $product):string
    {
        return $product->getdateCreate()->format('d.m.Y');
    }

    /**
     * @param ProductEntityInterface|Product $product
     * @return string
     */
    public function formatDateUpdate(ProductEntityInterface $product):string
    {
        return $product->getdateUpdate()->format('d.m.Y');
    }

    /**
     * @param DataTableEngine $table
     * @param array $categoriesAr
     * @param array $brandsAr
     * @param array $groupsAr
     * @param array $productGroupsIds
     * @throws \ReflectionException
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    protected function buildForm(DataTableEngine $table, array $categoriesAr, array $brandsAr, array $groupsAr, array $productGroupsIds): void
    {

        $images = self::$images;
        $imagesControls = [];
        $check = 1;

        $current = $table->loadFormEntity();


        foreach ($images as $image) {

            $imgUpload = $this->controlBuilder
                ->buildImgUpload($image, $this->catalogService->getProductsImageDir(), true, $this->mainConfig->getImagesServer())
                ->setPreviewImageSize(200)
                ->setPreviewImage(true);

            $imagesControls[] = $imgUpload;
        }


        $brandName = $categoryName = '';
        $brandId = $categoryId = null;

        if (input_get('id')) {
            $product = $this->productRepository->findById(input_get('id'));
            if ($product) {
                $brandName = $product->getBrand()->getName();
                $categoryName = $product->getCategory()->getNameWithParent();
            }
        } else {
            $brand = $this->brandRepository->findById($this->mainConfig->getDefaultBrandId());
            if ($brand) {
                $brandName = $brand->getName();
                $brandId = $brand->getId();
            }
            $category = $this->productCategoryRepository->findById($this->mainConfig->getDefaultCategoryId());
            if ($category) {
                $categoryName = $category->getTitle();
                $categoryId = $category->getId();
            }
        }


        $table
            ->addField(
                $this->controlBuilder->buildInput('title'), true
            )
            ->addField(
                $this->controlBuilder->buildInput('article')
            )
            ->addField(
                $this->controlBuilder->buildWindowSelect(
                    'categoryId',
                    '/admin/shop/catalog/categories-lite?filter=1',
                    $categoryName
                )->setValue($categoryId), true
            // $this->controlBuilder->buildAutoDropdown('categoryId', $categoriesAr), true
            )
            ->addField(
                $this->controlBuilder->buildWindowSelect(
                    'brandId',
                    '/admin/shop/catalog/brands-lite?filter=1',
                    $brandName
                )->setValue($brandId), true, 'Производитель'
            )
            ->addField(
                $this->controlBuilder->buildNiftySimpleSwitchery('active', 'Y', 'N'), true
            )
            ->addField(
                $this->controlBuilder->buildNiftySimpleSwitchery('special', 'Y', 'N'), true, 'Специальное предложение'
            )
            ->addField(
                $this->controlBuilder->buildTextArea('shortDesc'), false, 'Краткое описание'
            )
            ->addField(
                $this->controlBuilder->buildInputTiny('price')
            )
            ->addField(
                $this->controlBuilder->buildInput('weight')->setValue(0)
            )
            ->addField(
                $this->controlBuilder->buildInput('minQuality')
                    ->setValue(1), false, 'Минимальное кол-во товара в упаковке'

            )
            ->addField(
                $this->controlBuilder->buildTextEditor('desc')
                    ->setHeight(200)
                    ->setCompact(true), false, 'Описание'
            );


        foreach ($imagesControls as $k => $imgUpload) {

            $table->addField(
                $imgUpload, false, 'Изображение товара ' . $k
            );

            if ($file = $imgUpload->UploadImage()) {
                Form::addTableNotice(
                    Form::buildSuccessMessage(sprintf('Изображение %s успешно сохранено', $file))
                );
            } elseif ($imgUpload->deleteImage()) {
                Form::addTableNotice(
                    Form::buildErrorMessage('Изображение успешно удалено')
                );
            }
        }

        $table->addField(
            $this->controlBuilder->buildAutoDropdownMulti('groups', $groupsAr)->setValue($productGroupsIds), false, 'Группы товара'
        );


    }


    /**
     * @param ProductEntityInterface|Product $product
     * @return string
     */
    public function formatGroups(ProductEntityInterface $product): string
    {

        return implode(', ', $product->getGroupListArray());
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatPosCount(ProductEntityInterface $product): string
    {
        return anchor( admin_path('/shop/catalog/positions'), (string)$product->getPositionsCount(),['title'=>'Перейти к позициям'],[
            'filter' => 1,
            'filter_by_productId'=>$product->getId()
        ] );
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatImage(ProductEntityInterface $product): string
    {
        $html = '';

        foreach (self::$images as $image) {
            $img = $product->{'get' . $image}();
            if($img > ''){
                $thumbImagePath = \Shop\Presentation\Helpers\ProductHelper::getThumbImagePath($this->mainConfig,$img);
                $html .= '<img src="' . $thumbImagePath. '" class="img-sm img-circle" />';
            }

        }

        return $html;
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatActive(ProductEntityInterface $product): string
    {
        $data = [
            'class' => self::class,
            'id' => $product->getId(),
            'fn' => 'changeActive'
        ];
        return (new Switchery($data, $product->getActive() === 'Y'))->render();
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatSpecial(ProductEntityInterface $product): string
    {
        $data = [
            'class' => self::class,
            'id' => $product->getId(),
            'fn' => 'changeSpecial'
        ];
        return (new Switchery($data, $product->getSpecial() === 'Y'))->render();;
    }

    public function changeActive(int $id, bool $checked): void
    {
        /**
         * @var Product $user
         */
        $entity = $this->productRepository->findById($id);
        $entity->setActive($checked);
        $this->productRepository->save($entity);
    }

    public function changeSpecial(int $id, bool $checked): void
    {
        /**
         * @var Product $user
         */
        $entity = $this->productRepository->findById($id);
        $entity->setSpecial($checked);
        $this->productRepository->save($entity);
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatBrand(ProductEntityInterface $product): string
    {
        return $product->getBrand()->getName();
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatCategory(ProductEntityInterface $product): string
    {
        return $product->getCategory()->getNameWithParentName();
    }

    /**
     * @param ProductEntityInterface $product
     * @return string
     */
    public function formatArticle(ProductEntityInterface $product): string
    {
        if (!$product->getArticle()) {
            return '';
        }
        $text = Text::clearText($product->getArticle(), 20);
        return $text . ($text !== $product->getArticle() ? '...' : '');
    }

}