<?php

namespace KupShop\ContentBundle\Resources\upgrade;

use Doctrine\DBAL\Exception\TableNotFoundException;
use KupShop\ContentBundle\Exception\UnknownPageTypeException;
use KupShop\ContentBundle\Util\PageLocator;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use Query\Operator;

class PageUpgrade extends \UpgradeNew
{
    protected $priority = -200;

    public function check_PagesTable()
    {
        return $this->checkTableExists('pages');
    }

    /** Create 'pages' table */
    public function upgrade_PagesTable()
    {
        sqlQuery('CREATE TABLE pages (
                id INT(11) PRIMARY KEY AUTO_INCREMENT,
                id_block INT(11) UNSIGNED NULL,
                name VARCHAR(50) NULL,
                code VARCHAR(50) NOT NULL UNIQUE,
                type VARCHAR(20) NOT NULL,
                url VARCHAR(50) DEFAULT NULL,
                CONSTRAINT FK_id_block_pages
                FOREIGN KEY (id_block) REFERENCES blocks (id)
                ON UPDATE CASCADE ON DELETE SET NULL
            )');

        $this->upgradeOK();
    }

    public function check_UpdatedColumn()
    {
        return $this->checkColumnExists('pages', 'updated');
    }

    /** Add `updated` column to `pages` table */
    public function upgrade_UpdatedColumn()
    {
        sqlQuery('ALTER TABLE `pages` ADD COLUMN `updated` TIMESTAMP NULL');

        $this->upgradeOK();
    }

    public function check_TypeLength(): bool
    {
        return $this->checkColumnType('pages', 'type', 'VARCHAR(100)');
    }

    /** Modify type length */
    public function upgrade_TypeLength(): void
    {
        sqlQuery('alter table pages modify type varchar(100) not null;');
        $this->upgradeOK();
    }

    public function check_PagesDefaultContent()
    {
        if (isFunctionalTests()) {
            return false;
        }

        $pages = sqlQueryBuilder()
            ->select('*')->from('pages')
            ->where('`updated` IS NULL')
            ->execute();

        if ($pages->rowCount()) {
            return true;
        }

        if (findModule(\Modules::TRANSLATIONS)) {
            try {
                $translations = sqlQueryBuilder()
                    ->select('p.*')->from('pages', 'p')
                    ->leftJoin('p', 'blocks', 'b', 'b.id_root=p.id_block')
                    ->leftJoin('b', 'blocks_translations', 't', 't.id_block = b.id')
                    ->where('t.updated IS NULL')
                    ->groupBy('p.id')
                    ->execute();

                if ($translations->rowCount()) {
                    return true;
                }
            } catch (TableNotFoundException $e) {
                // blocks_translations jeste nemusi existovat a nevim jestli by vadilo, kdybych dal tomuhle upgradu jinou prioritu, tak radsi takhle
                return false;
            }
        }

        return false;
    }

    /** update default Pages content */
    public function upgrade_PagesDefaultContent()
    {
        $pages = sqlFetchAll(sqlQueryBuilder()
            ->select('*')->from('pages')->where('`updated` IS NULL')
            ->execute(),
            'id');

        if (findModule(\Modules::TRANSLATIONS)) {
            $translations = sqlFetchAll(sqlQueryBuilder()
                ->select("p.*, NULLIF(CONCAT_WS('-', t.updated), '') concat_updated")->from('pages', 'p')
                ->leftJoin('p', 'blocks', 'b', 'b.id_root=p.id_block')
                ->leftJoin('b', 'blocks_translations', 't', 't.id_block = b.id')
                ->having('concat_updated IS NULL')
                ->groupBy('p.id')
                ->execute(),
                'id');

            if ($translations) {
                $pages = $pages + $translations;
            }
        }

        if ($pages) {
            /** @var PageLocator $pageLocator */
            $pageLocator = ServiceContainer::getService(PageLocator::class);
            foreach ($pages as $row) {
                try {
                    $page = $pageLocator->getPageService($row['type']);
                } catch (UnknownPageTypeException $e) {
                    // pokud stranka existuje v DB, ale neexistuje k ni servisa, tak chybu ignoruju
                    // a stranku preskakuju - pravdepodobne je to smazana systemova stranka, ktera zustala jen v DB
                    continue;
                }
                if ($json_contents = $page->getDefaultJson()) {
                    $blocks = sqlQueryBuilder()->select('*')
                        ->from('blocks')
                        ->where('id_root=:id_root')->setParameter('id_root', $row['id_block'])
                        ->orderBy('position')
                        ->execute()->fetchAll();

                    $json_contents = json_decode($json_contents, true);
                    $areas = $json_contents['areas'] ?? [$json_contents];

                    $update = false;
                    for ($i = 0; $i < max(count($blocks), count($areas)); $i++) {
                        $area = $areas[$i] ?? null;
                        $block = $blocks[$i] ?? null;

                        if (!$area && $block) {
                            sqlQueryBuilder()->delete('blocks')->where(Operator::equals(['id' => $block['id']]))->execute();
                        } elseif ($area && !$block) {
                            sqlQueryBuilder()->insert('blocks')
                                ->directValues(['id_parent' => $row['id_block'],
                                    'id_root' => $row['id_block'],
                                    'content' => '',
                                    'json_content' => '', ])->execute();
                            $blocks[$i]['id'] = sqlInsertId();
                            $update = true;
                        } elseif ($row['updated'] || (md5($block['json_content']) !== md5(json_encode($area)))) {
                            $update = true;
                        }
                    }

                    if ($update) {
                        $page->generateDefaultContent(array_map(function ($val) {
                            return $val['id'];
                        }, $blocks));
                    }
                }
            }
        }
    }

    public function check_PagesTypeVarcharLength30()
    {
        return !$this->checkColumnType('pages', 'type', 'varchar(20)')
            && $this->checkColumnType('pages', 'type', 'varchar(30)');
    }

    /** Increase pages type varchar length to 30  */
    public function upgrade_PagesTypeVarcharLength30()
    {
        sqlQuery('
            alter table pages
                modify type varchar(30) not null;
        ');
    }

    public function check_PagesDataColumn()
    {
        return $this->checkColumnExists('pages', 'data');
    }

    /** Add data column to pages table  */
    public function upgrade_PagesDataColumn()
    {
        sqlQuery('ALTER TABLE pages ADD COLUMN data MEDIUMTEXT DEFAULT NULL');
    }
}
