<?php

namespace idoit\Module\Forms\Model\CategoryTypes;

use idoit\Module\Multiedit\Component\Multiedit\Exception\CategoryDataException;
use idoit\Module\Multiedit\Model\SpecificCategories as CategoryModel;
use isys_component_database;
use isys_application;

/**
 * Can be removed after 1.18.
 */
class SpecificCategories extends CategoryModel
{
  /**
   * @return SpecificCategories
   * @throws CategoryDataException
   */
  public function setData(): SpecificCategories
  {
    $blockListAsString = implode(',', $this->getBlacklist());
    $supportedCategoryTypes = implode(',', $this->getSupportedCategoryTypes());
    $container = isys_application::instance()->container;
    $language = $container->get('language');
    $categoryFilterCondition = '';
    $condition = [];

    try {
      $query = "SELECT *, (
                SELECT GROUP_CONCAT(DISTINCT(subQ.isys_obj_type__title) SEPARATOR ', ') FROM    (
                        SELECT *, 1 AS 'check' FROM isys_obj_type
                        LEFT JOIN `isysgui_cats_2_subcategory` ON `isysgui_cats_2_subcategory__isysgui_cats__id__parent` = isys_obj_type__isysgui_cats__id OR `isysgui_cats_2_subcategory__isysgui_cats__id__child` = isys_obj_type__isysgui_cats__id
                        WHERE isys_obj_type__isysgui_cats__id IS NOT NULL
                    ) AS subQ
                 WHERE subQ.isysgui_cats_2_subcategory__isysgui_cats__id__child = main.isysgui_cats__id OR
                    subQ.isysgui_cats_2_subcategory__isysgui_cats__id__parent = main.isysgui_cats__id OR
                    subQ.isys_obj_type__isysgui_cats__id = main.isysgui_cats__id
            ) AS objTypes

            FROM isysgui_cats main
            LEFT JOIN isys_property_2_cat propCat ON propCat.isys_property_2_cat__isysgui_cats__id = main.isysgui_cats__id
            WHERE main.isysgui_cats__type IN ({$supportedCategoryTypes}) AND main.isysgui_cats__id NOT IN ({$blockListAsString}) AND
            !LOCATE('_ROOT', main.isysgui_cats__const) %s";

      $filter = $this->getFilter();

      if (!empty($filter->getObjects())) {
        $condition[] = ' main.isysgui_cats__id IN (
                    SELECT isys_obj_type__isysgui_cats__id FROM (
                        SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                            SELECT DISTINCT isys_obj__isys_obj_type__id FROM isys_obj WHERE isys_obj__id IN (' . implode(',', $filter->getObjects()) . ')
                        )
                        UNION
                        SELECT isysgui_cats_2_subcategory__isysgui_cats__id__child FROM isysgui_cats_2_subcategory WHERE isysgui_cats_2_subcategory__isysgui_cats__id__parent IN (
                            SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                                SELECT DISTINCT isys_obj__isys_obj_type__id FROM isys_obj WHERE isys_obj__id IN (' . implode(',', $filter->getObjects()) . ')
                            )
                        )
                        UNION
                        SELECT isysgui_cats_2_subcategory__isysgui_cats__id__parent FROM isysgui_cats_2_subcategory WHERE isysgui_cats_2_subcategory__isysgui_cats__id__child IN (
                            SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                                SELECT DISTINCT isys_obj__isys_obj_type__id FROM isys_obj WHERE isys_obj__id IN (' . implode(',', $filter->getObjects()) . ')
                            )
                        )
                    ) AS filterCategory)';
      }

      if (empty($filter->getObjects()) && !empty($filter->getObjectTypes())) {
        $objectTypes = $filter->getObjectTypes();
        $objectTypes = array_filter($objectTypes, 'defined');

        if (!empty($objectTypes)) {
          $objectTypes = array_map('defined_or_default', $objectTypes);

          $condition[] = ' main.isysgui_cats__id IN (
                    SELECT isys_obj_type__isysgui_cats__id FROM (
                        SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                            ' . implode(', ', $objectTypes) . '
                        )
                        UNION
                        SELECT isysgui_cats_2_subcategory__isysgui_cats__id__child FROM isysgui_cats_2_subcategory WHERE isysgui_cats_2_subcategory__isysgui_cats__id__parent IN (
                            SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                                ' . implode(', ', $objectTypes) . '
                            )
                        )
                        UNION
                        SELECT isysgui_cats_2_subcategory__isysgui_cats__id__parent FROM isysgui_cats_2_subcategory WHERE isysgui_cats_2_subcategory__isysgui_cats__id__child IN (
                            SELECT isys_obj_type__isysgui_cats__id FROM isys_obj_type WHERE isys_obj_type__id IN (
                                ' . implode(', ', $objectTypes) . '
                            )
                        )
                    ) AS filterCategory)';
        }
      }

      $categories = $filter->getCategories();

      if (!empty($categories) && !in_array('*', $categories)) {
        $categoryFilterCondition = ' main.isysgui_cats__const IN (\'' . implode('\',\'', $categories) . '\')';
        if (is_numeric($categories[0])) {
          $categoryFilterCondition = ' main.isysgui_cats__id IN (' . implode(',', $categories) . ')';
        }
        $condition[] = $categoryFilterCondition;
      }

      $result = $this->retrieve(sprintf($query, (!empty($condition) ? ' AND ' . implode(' AND ', $condition) : '')));

      while ($row = $result->get_row()) {
        // @see  ID-6622  This should prevent errors after categories have been removed.
        if (!class_exists($row['isysgui_cats__class_name'])) {
          continue;
        }

        $this->data[$this->getType() . '_' . $row['isysgui_cats__id'] . ':' . $row['isysgui_cats__class_name']] =
            $language->get($row['isysgui_cats__title']);
        $this->increment();

        $checkSql = 'SELECT isys_property_2_cat__prop_key FROM isys_property_2_cat
                    WHERE isys_property_2_cat__cat_const = ' . $this->convert_sql_text($row['isysgui_cats__const']) . '
                        AND isys_property_2_cat__prop_type = ' . $this->convert_sql_int(C__PROPERTY_TYPE__STATIC) . '
                        AND isys_property_2_cat__prop_key != ' . $this->convert_sql_text('description') . '
                        AND isys_property_2_cat__prop_provides & ' . $this->convert_sql_int(C__PROPERTY__PROVIDES__MULTIEDIT);

        $checkResult = $this->retrieve($checkSql);
        $numProperties = $checkResult->num_rows();

        if ($numProperties === 1) {
          $propKey = $checkResult->get_row_value('isys_property_2_cat__prop_key');
          $catDao = $row['isysgui_cats__class_name']::instance($container->get('database'));
          $properties = $catDao->get_properties();
          $property = $properties[$propKey];

          if ((int)$property[C__PROPERTY__INFO][C__PROPERTY__INFO__TYPE] === C__PROPERTY__INFO__TYPE__OBJECT_BROWSER ||
            (int)$property[C__PROPERTY__INFO][C__PROPERTY__INFO__TYPE] === C__PROPERTY__INFO__TYPE__N2M) {
            continue;
          }
        } elseif ($numProperties === 0) {
          // Remove category from list, because there are no properties which are usable for the multiedit list
          unset($this->data[$this->getType() . '_' . $row['isysgui_cats__id'] . ':' . $row['isysgui_cats__class_name']]);
          $this->decrement();
          continue;
        }

        if ($row['isysgui_cats__list_multi_value'] > 0) {
          $this->addToMultivalueCategories($row['isysgui_cats__id']);
        }
      }

      return $this;
    } catch (\Exception $e) {
      throw new CategoryDataException('Collecting specific categories failed in File : ' . $e->getFile() . ' on Line: ' . $e->getLine() . ' with Message: ' . $e->getMessage());
    }
  }
}
