<?php

namespace Shop\Commands;

use Diamond\Repositories\Page\PageCriteria;
use Shop\Application\Office\OfficeService;
use Shop\Repositories\Product\ProductCriteria;
use Shop\Repositories\ProductCategory\ProductCategoryCriteria;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use samdark\sitemap\Sitemap as SitemapLib;
use Diamond\Repositories\Page\PageRepository as pageRepo;
use Shop\Repositories\Product\ProductRepository as productRepo;
use Shop\Repositories\ProductCategory\ProductCategoryRepository as categoryRepo;

/**
 * Description of SitemapCommand
 *
 * @author Admin
 */
class Sitemap extends Command
{

    protected $pageRepo;
    protected $productRepo;
    protected $categoryRepo;
    protected $mainConf;
    protected $officeService;

    /**
     * Sitemap constructor.
     * @param null $name
     * @param OfficeService $officeService
     * @param \Diamond\Config\Main $mainConf
     * @param pageRepo $pageRepo
     * @param productRepo $productRepo
     * @param categoryRepo $categoryRepo
     * @throws \Symfony\Component\Console\Exception\LogicException
     */
    public function __construct($name = null,
                                OfficeService $officeService,
                                \Diamond\Config\Main $mainConf,
                                pageRepo $pageRepo,
                                productRepo $productRepo,
                                categoryRepo $categoryRepo)
    {
        $this->officeService = $officeService;
        $this->pageRepo = $pageRepo;
        $this->productRepo = $productRepo;
        $this->categoryRepo = $categoryRepo;
        $this->mainConf = $mainConf;

        parent::__construct($name);
    }

    protected function configure()
    {
        $this->setName('tools:sitemap')
            ->setDescription('Create simemap.xml');
    }

    /**
     * @param SitemapLib $sitemap
     * @throws \InvalidArgumentException
     * @throws \Repo\Concrete\Exceptions\Collection
     */
    protected function createPages(SitemapLib $sitemap)
    {

        $pages = $this->pageRepo->findByCriteria(
            PageCriteria::create()->setFilterByActive(true)
                ->setFilterBySystem(false)
                ->setFilterBySiteId(1)
        );

        foreach ($pages as $page) {

            $url = $page->getUrl();

            if (
                stripos($url, '/personal') !== false ||
                stripos($url, '/registration') !== false ||
                stripos($url, '/recovery') !== false ||
                stripos($url, '/payment/paymaster') !== false
            ) {
                continue;
            }

            $sitemap->addItem(
                $this->createUrl($url)
                , time(), SitemapLib::DAILY, 1);
        }

    }

    /**
     * @param string $_url
     * @return string
     */
    protected function createUrl(string $_url): string
    {
        $conf = $this->mainConf;
        $urlSuffix = $_url . $conf->getUrl_suffix();
        if ($urlSuffix === '/' . $conf->getUrl_suffix()) {
            $urlSuffix = '/';
        }
        return str_replace(
            ' ','',
            trim(getenv('BASE_URL'), '/') . $urlSuffix
        );
    }

    /**
     * @param SitemapLib $sitemap
     * @throws \InvalidArgumentException
     * @throws \Repo\Concrete\Exceptions\Collection
     * @throws \RuntimeException
     */
    protected function createCatalogPages(SitemapLib $sitemap): void
    {
        $customer = $this->officeService->getCurrentCustomer();

        if(!$customer){
            throw new \RuntimeException('customer not set');
        }

        $categories = $this->categoryRepo->findByCriteria(
            ProductCategoryCriteria::create()->setFilterByPriceListIds($customer->getAccessPriceListScheetIds())
        );

        foreach ($categories as $category) {

            $sitemap->addItem(
                $this->createUrl(sprintf(
                    '/catalog/%s', $category->getAlias()
                ))
                , time(), SitemapLib::DAILY, 0.9);
        }
    }

    /**
     * @param SitemapLib $sitemap
     * @throws \InvalidArgumentException
     * @throws \Repo\Concrete\Exceptions\Collection
     * @throws \RuntimeException
     */
    protected function createProductPages(SitemapLib $sitemap): void
    {
        $customer = $this->officeService->getCurrentCustomer();

        if(!$customer){
            throw new \RuntimeException('customer not set');
        }

        $products = $this
            ->productRepo->findByCriteria(ProductCriteria::create()
                ->setFilterByPriceListScheetIds($customer->getAccessPriceListScheetIds())
                ->setFilterByActive(true));

        foreach ($products as $product) {

            $sitemap->addItem(
                $this->createUrl(
                    sprintf(
                        '/catalog/%s/%s-%s', $product->getCategory()->getAlias(), $product->getId(),
                        \Shop\Helpers\Text::str2url($product->getTitle())
                    ))
                , time(), SitemapLib::DAILY, 0.8);
        }
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @throws \InvalidArgumentException
     * @throws \Repo\Concrete\Exceptions\Collection
     * @throws \RuntimeException
     */
    protected function execute(InputInterface $input, OutputInterface $output): void
    {

        $sitemap = new SitemapLib(BASEPATH . '/public_html/sitemap.xml');

        //Генерируем страницы
        $this->createPages($sitemap);

        //Генерируем страницы разделов каталога
        $this->createCatalogPages($sitemap);
        //генерируем страницы товаров
        $this->createProductPages($sitemap);

        try {
            $sitemap->write();
            $output->writeln('sitemap.xml create completed!');
        } catch (\Exception $ex) {
            $output->writeln('sitemap.xml create error!');
        }
    }

}