<?php

use Espo\Core\Container;
use Espo\Core\InjectableFactory;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Config\ConfigWriter;
use Espo\Core\Utils\Metadata;
use Espo\ORM\EntityManager;

class AfterInstall
{
    /** @noinspection PhpUnhandledExceptionInspection */
    public function run(Container $container)
    {
        $metadata = $container->getByClass(Metadata::class);
        $config = $container->getByClass(Config::class);
        $entityManager = $container->getByClass(EntityManager::class);
        $configWriter = $container->getByClass(InjectableFactory::class)->create(ConfigWriter::class);

        $this->addProjectParent($config, $metadata);
        $this->addTabs($config, $configWriter);
        $this->createBoard($entityManager);
        $this->addAdminIframeUrl($config, $configWriter);
    }

    private function addProjectParent(Config $config, Metadata $metadata): void
    {
        $activitiesEntityTypeList = $config->get('activitiesEntityList', []);
        $historyEntityTypeList = $config->get('historyEntityList', []);

        $entityTypeList = array_merge($activitiesEntityTypeList, $historyEntityTypeList);
        $entityTypeList = array_unique($entityTypeList);

        foreach ($entityTypeList as $entityType) {
            if (!$metadata->get(['entityDefs', $entityType, 'fields', 'parent', 'entityList'])) {
                continue;
            }

            $list = $metadata->get(['entityDefs', $entityType, 'fields', 'parent', 'entityList'], []);

            if (in_array('Project', $list)) {
                continue;
            }

            $list[] = 'Project';

            $data = [
                'fields' => [
                    'parent' => ['entityList' => $list]
                ],
            ];

            $metadata->set('entityDefs', $entityType, $data);
        }

        $metadata->save();
    }

    private function addTabs(Config $config, ConfigWriter $configWriter): void
    {
        /** @var (string|stdClass)[] $tabList */
        $tabList = $config->get('tabList', []);
        /** @var string[] $quickCreateList */
        $quickCreateList = $config->get('quickCreateList', []);

        if (!$this->isInTabList('Project', $tabList)) {
            $tabList[] = (object) [
                'type' => 'divider',
                'text' => null,
                'id' => $this->generateTabId(),
            ];

            $tabList[] = 'Project';
            $tabList[] = 'ProjectTask';

            $configWriter->set('tabList', $tabList);
        }

        if (!in_array('ProjectTask', $quickCreateList)) {
            $quickCreateList[] = 'ProjectTask';

            $configWriter->set('quickCreateList', $quickCreateList);
        }

        $configWriter->save();
    }

    /**
     * @param (string|stdClass)[] $tabList
     * @noinspection PhpSameParameterValueInspection
     */
    private function isInTabList(string $entityType, array $tabList): bool
    {
        if (in_array($entityType, $tabList)) {
            return true;
        }

        foreach ($tabList as $tab) {
            if (is_string($tab)) {
                continue;
            }

            /** @var (string|stdClass)[] $itemList */
            $itemList = $tab->itemList ?? [];

            if (in_array($entityType, $itemList)) {
                return true;
            }
        }

        return false;
    }

    private function generateTabId(): string
    {
        return (string) rand(100000, 999999);
    }

    private function createBoard(EntityManager $entityManager): void
    {
        if ($entityManager->getRDBRepository('ProjectBoard')->findOne()) {
            return;
        }

        $entityManager->createEntity('ProjectBoard', [
            'name' => 'Default',
        ], ['createColumns' => true]);
    }

    private function addAdminIframeUrl(Config $config, ConfigWriter $configWriter): void
    {
        /** @var ?string $url */
        $url = $config->get('adminPanelIframeUrl');

        if (empty($url) || trim($url) == '/') {
            $url = 'https://s.espocrm.com/';
        }

        $url = $this->addUrlParam($url, 'instanceId', $config->get('instanceId'));
        $url = $this->addUrlParam($url, 'project-management', 'f27e70ce6801a13265271f5669c8bc5c');

        if ($url == $config->get('adminPanelIframeUrl')) {
            return;
        }

        $configWriter->set('adminPanelIframeUrl', $url);
        $configWriter->save();
    }

    private function addUrlParam(string $url, string $paramName, $paramValue): string
    {
        $urlQuery = parse_url($url, PHP_URL_QUERY);

        if (!$urlQuery) {
            $params = [
                $paramName => $paramValue
            ];

            $url = trim($url);
            /** @var string $url */
            $url = preg_replace('/\/\?$/', '', $url);
            /** @var string $url */
            $url = preg_replace('/\/$/', '', $url);

            return $url . '/?' . http_build_query($params);
        }

        parse_str($urlQuery, $params);

        if (!isset($params[$paramName]) || $params[$paramName] != $paramValue) {
            $params[$paramName] = $paramValue;

            return str_replace($urlQuery, http_build_query($params), $url);
        }

        return $url;
    }
}
