<?php

namespace idoit\Module\Cmdb\Search\Index\Data\Source\Category;

use idoit\Module\Cmdb\Search\Index\Data\CategoryCollector;
use idoit\Module\Search\Index\Data\Source\Config;
use idoit\Module\Search\Index\Document;
use idoit\Module\Search\Index\Engine\SearchEngine;
use isys_tenantsettings;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

class isys_cmdb_dao_category_g_custom_fields extends AbstractCategorySource
{
    /**
     * Get identifier for indexable data source
     *
     * @return string
     */
    public function getIdentifier()
    {
        return 'C__CATEGORY__CUSTOM';
    }

    /**
     * Retrieve data for index creation
     *
     * @param Config $config
     *
     * @return array
     */
    public function retrieveData(Config $config)
    {
        $simpleTypes = ['f_text', 'f_textarea', 'f_link', 'f_wysiwyg', 'commentary'];

        $complexTypes = ['f_popup' => 'retrieveSqlForDialogEntries'];

        $sql = sprintf("SELECT CONCAT(isys_obj__isys_obj_type__id, isys_obj__id, '.custom_fields.', isys_catg_custom_fields_list__data__id, '.', REPLACE(isysgui_catg_custom__title, '.', '_'), '.', isysgui_catg_custom__id, '.', isys_catg_custom_fields_list__field_key) index_key, isys_catg_custom_fields_list__field_content, isys_obj__id 
             FROM isys_catg_custom_fields_list
             INNER JOIN isysgui_catg_custom ON isysgui_catg_custom.isysgui_catg_custom__id = isys_catg_custom_fields_list.isys_catg_custom_fields_list__isysgui_catg_custom__id
             INNER JOIN isys_obj obj ON (isys_catg_custom_fields_list.isys_catg_custom_fields_list__isys_obj__id = obj.isys_obj__id)
             WHERE isys_catg_custom_fields_list__field_type IN (%s) AND obj.isys_obj__isys_obj_type__id NOT IN (%s)", '"' . implode('", "', $simpleTypes) . '"',
            implode(', ', CategoryCollector::BLACKLISTED_OBJECT_TYPES));

        if ($config->hasObjectIds()) {
            $sql .= " AND obj.isys_obj__id IN (" . implode(', ', $config->getObjectIds()) . ")";
        }

        if (!isys_tenantsettings::get('search.index.include_archived_deleted_objects', false)) {
            $sql .= ' AND obj.isys_obj__status = '  . C__RECORD_STATUS__NORMAL;
        }

        $this->eventDispatcher->dispatch('index.data.raw.execute_sql', new GenericEvent($this, [
            'sql' => $sql
        ]));

        $resource = $this->database->query($sql);

        $complexTypeResources = [];

        foreach ($complexTypes as $complexType => $callable) {
            $sql = $this->{$callable}($config);

            $this->eventDispatcher->dispatch('index.data.raw.execute_sql', new GenericEvent($this, [
                'sql' => $sql
            ]));

            $complexTypeResources[$complexType] = $this->database->query($sql);
        }

        $complexTypeRows = 0;

        foreach ($complexTypeResources as $complexType => $resource) {
            $complexTypeRows += $this->database->num_rows($resource);
        }

        if ($this->database->num_rows($resource) !== 0 || $complexTypeRows !== 0) {
            $data = [];

            $this->eventDispatcher->dispatch('index.data.raw.progress.start', new GenericEvent($this, [
                'count'   => $this->database->num_rows($resource) + $complexTypeRows,
                'context' => $this->categoryDao->get_category_const()
            ]));

            while ($row = $this->database->fetch_row_assoc($resource)) {
                $data[] = $row;
                $this->eventDispatcher->dispatch('index.data.raw.progress.advance', new GenericEvent($this));
            }

            foreach ($complexTypeResources as $complexType => $resource) {
                while ($row = $this->database->fetch_row_assoc($resource)) {
                    $data[] = $row;
                    $this->eventDispatcher->dispatch('index.data.raw.progress.advance', new GenericEvent($this));
                }
            }

            $this->eventDispatcher->dispatch('index.data.raw.progress.finish', new GenericEvent($this, [
                'count' => $this->database->num_rows($resource)
            ]));

            return $data;
        }

        return [];
    }

    /**
     * Map data from retrieveData to Documents
     *
     * @param array $data
     *
     * @return Document[]
     */
    public function mapDataToDocuments(array $data)
    {
        $documents = [];

        foreach ($data as $set) {
            $document = new Document();
            $document->setVersion(SearchEngine::VERSION);
            $document->setType('cmdb');
            $document->setKey($set['index_key']);
            $document->setValue(filter_var(html_entity_decode($set['isys_catg_custom_fields_list__field_content']), FILTER_SANITIZE_STRING));
            $document->setReference($set['isys_obj__id']);

            $documents[$document->getKey()] = $document;
        }

        return $documents;
    }

    private function retrieveSqlForDialogEntries(Config $config) {
        $sql = sprintf("SELECT CONCAT(isys_obj__isys_obj_type__id, isys_obj__id, '.custom_fields.', isys_catg_custom_fields_list__data__id, '.', REPLACE(isysgui_catg_custom__title, '.', '_'), '.', isysgui_catg_custom__id, '.', isys_catg_custom_fields_list__field_key) index_key, GROUP_CONCAT(isys_dialog_plus_custom__title separator ', ') as isys_catg_custom_fields_list__field_content, isys_obj__id 
             FROM isys_catg_custom_fields_list
             INNER JOIN isysgui_catg_custom ON isysgui_catg_custom.isysgui_catg_custom__id = isys_catg_custom_fields_list.isys_catg_custom_fields_list__isysgui_catg_custom__id
             INNER JOIN isys_obj obj ON (isys_catg_custom_fields_list.isys_catg_custom_fields_list__isys_obj__id = obj.isys_obj__id)
             INNER JOIN isys_dialog_plus_custom ON (isys_catg_custom_fields_list__field_content = isys_dialog_plus_custom__id)
             WHERE isys_catg_custom_fields_list__field_type IN (%s) AND obj.isys_obj__isys_obj_type__id NOT IN (%s) GROUP BY isys_catg_custom_fields_list__field_content", '"' . implode('", "', ['f_popup']) . '"',
            implode(', ', CategoryCollector::BLACKLISTED_OBJECT_TYPES));

        if ($config->hasObjectIds()) {
            $sql .= " AND obj.isys_obj__id IN (" . implode(', ', $config->getObjectIds()) . ")";
        }

        if (!isys_tenantsettings::get('search.index.include_archived_deleted_objects', false)) {
            $sql .= ' AND obj.isys_obj__status = '  . C__RECORD_STATUS__NORMAL;
        }

        return $sql;
    }
}
