<?php

/**
 * @package     Joomla.Site
 * @subpackage  com_formea
 *
 * @copyright   Copyright (C) 2010-2025 Feseur Sdn Bhd. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 * @version     1.3.0
 */

namespace Joomla\Component\Formea\Site\Libraries;

defined('_JEXEC') or die;

use Feseur\Library\FsrDate;
use Feseur\Library\FsrFieldQuery;
use Joomla\CMS\Factory;
use Joomla\Component\Formea\Site\Helper\FormeaGeneralHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Registry\Registry;

class FormeaGridOperations
{
  public $form_id;
  public $group_id;
  public $type;
  public $page_id;
  public $settingRegistry;

  public $isPreview;

  protected $elementsRaw;

  protected $elements;

  /**
   * @var DatabaseDriver
   * @since 1.0.0
   */
  protected $db;

  /**
   * @var FormeaElement[]
   * @since 1.0.0
   */
  protected $elementClasses = [];

  /**
   * @var FormeaGroupedElement[]
   * @since 1.0.3
   */
  protected $groupedElementClasses = [];

  public $formUniqueString;

  /**
   * @var FormeaTheme | null
   * @since 1.0.0
   */
  protected $themeClass;

  protected $app;

  protected $user;

  protected $rawGroups;

  public $groupLayouts;

  protected $setIndex = 0;

  /**
   * @var FormeaCore[]
   * @since 1.0.3
   */
  protected $coreClasses;

  public function __construct($target_id, $type = 0, $config = [])
  {
    $settingRegistry  = false;
    $isPreview        = false;
    $elementClasses   = [];
    $formUniqueString = '';
    $this->type       = $type;
    $themeClass       = null;
    $this->app        = Factory::getApplication();

    if ($type > 0) {
      $this->group_id = $target_id;
      $this->form_id  = 0;
    } else {
      $this->form_id  = $target_id;
      $this->group_id = 0;
    }


    if (isset($config['page_id'])) {
      $this->page_id = $config['page_id'];
    } else {
      $this->page_id = 0;
    }
    if (isset($config['settingRegistry'])) {
      $settingRegistry = $config['settingRegistry'];
    }
    if (isset($config['isPreview'])) {
      $isPreview = $config['isPreview'];
    }
    if (isset($config['elementClasses'])) {
      $elementClasses = $config['elementClasses'];
    }
    if (isset($config['formUniqueString'])) {
      $formUniqueString = $config['formUniqueString'];
    }

    if (isset($config['setIndex'])) {
      $this->setIndex = $config['setIndex'];
    }

    if (isset($config['themeClass'])) {
      $themeClass = $config['themeClass'];
    }

    if (isset($config['coreClasses'])) {
      $this->coreClasses = $config['coreClasses'];
    } else {
      $this->coreClasses = [new FormeaCore()];
    }

    if (isset($config['form_id'])) {
      $this->form_id = $config['form_id'];
    }
    $this->user             = $this->app->getIdentity();
    $this->themeClass       = $themeClass;
    $this->formUniqueString = $formUniqueString;
    $this->settingRegistry  = $settingRegistry;
    $this->isPreview        = $isPreview;
    $this->elementClasses   = $elementClasses;
    $container              = Factory::getContainer();
    $this->db               = $container->get('DatabaseDriver');
  }

  /**
   * @param                    $preview
   * @param   FsrFieldQuery[]  $whereClause
   *
   * @return array|mixed
   *
   * @since 1.0.0
   */
  public function getElementsRaw($whereClause = [])
  {
    if (empty($this->elementsRaw)) {
      $db    = $this->db;
      $query = $db->getQuery(true);
      $query->select([
        'a.element_id',
        'a.labelSettings',
        'a.type',
        'a.group_id',
        'a.page_id',
        'b.title',
        'b.alias',
        'b.type',
        'b.state',
        'COALESCE(d.group_type, -1) AS group_type',
        'COALESCE(d.state, -1) AS group_state'
      ]);
      $query->from($db->quoteName('#__formea_form_elements', 'a'));
      $query->innerJoin(
        $db->quoteName('#__formea_elements', 'b') . ' ON ' .
          $db->quoteName('a.element_id') . ' = ' . $db->quoteName('b.id')
      );
      $query->innerJoin(
        $db->quoteName('#__formea_eltypes', 'c') . ' ON ' .
          $db->quoteName('b.type') . ' = ' . $db->quoteName('c.name')
      );
      $query->leftJoin(
        $db->quoteName('#__formea_groups', 'd') . ' ON ' .
          $db->quoteName('a.group_id') . ' = ' . $db->quoteName('d.id')
      );
      if (!$this->isPreview) {

        $query->where($db->quoteName('b.state') . ' = ' . $db->quote(1));
        $query->where($db->quoteName('c.state') . ' = ' . $db->quote(1));

        $groups = $this->user->getAuthorisedViewLevels();
        $query->where($db->quoteName('b.access_level') . ' IN (' . implode(',', $groups) . ')');
        $nowDate = (new FsrDate())->toSql();
        $query->extendWhere(
          'AND',
          [
            $db->quoteName('b.publish_up') . ' IS NULL',
            $db->quoteName('b.publish_up') . ' <= :publishUp',
          ],
          'OR'
        )
          ->extendWhere(
            'AND',
            [
              $db->quoteName('b.publish_down') . ' IS NULL',
              $db->quoteName('b.publish_down') . ' >= :publishDown',
            ],
            'OR'
          )
          ->bind([':publishUp', ':publishDown'], $nowDate);
      }

      if ($this->type == 0) {
        $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($this->form_id));
      } else {
        $query->where($db->quoteName('a.group_id') . ' = ' . $db->quote($this->group_id));
      }

      $query->where($db->quoteName('a.target_type') . ' = ' . $db->quote($this->type));

      if (!empty($whereClause)) {
        foreach ($whereClause as $clause) {
          $v = $db->quote($clause->value);
          if ($clause->value[0] == '(' && $clause->value[strlen($clause->value) - 1] == ')') {
            $v = $clause->value;
          }
          $query->where(
            $db->quoteName($clause->field) . ' ' .
              $clause->operator . ' ' .
              $v
          );
        }
      }
      $query->order('a.id ASC');
      $db->setQuery($query);
      $this->elementsRaw = $db->loadObjectList();
    }

    return $this->elementsRaw;
  }

  public function getElements($whereClause = [])
  {
    if (empty($this->elements)) {

      $elements    = [];
      $ids         = [];
      $rawElements = $this->getElementsRaw($whereClause);
      /* var_dump($rawElements);
         die;
         $_rawElements = [];
         if (!empty($rawElements))
         {
           $totalRawElements = count($rawElements);
           for ($i = 0; $i < $totalRawElements; $i++)
           {
           $ids[]                                                                         = $rawElements[$i]->element_id;
           $_rawElements[$rawElements[$i]->element_id . '_' . $rawElements[$i]->group_id] = $rawElements[$i];
           }

           $db    = $this->db;
           $query = $db->getQuery(true);
           $query->select([
           'a.id AS element_id',
           'a.title',
           'a.alias',
           'a.type',
           ]);
           $query->from($db->quoteName('#__formea_elements', 'a'))
           ->leftJoin($db->quoteName('#__formea_element_validations', 'b') . ' ON ' .
             $db->quoteName('a.id') . ' = ' . $db->quoteName('b.element_id')
           );
           $query->where($db->quoteName('a.id') . ' IN (' . implode(',', $ids) . ')');
           $db->setQuery($query);
           $elements = $db->loadObjectList();
           if (!empty($elements))
           {
           $totalElements = count($elements);
           for ($j = 0; $j < $totalElements; $j++)
           {
             $elements[$j]->group_id = $_rawElements[$elements[$j]->element_id]->group_id;
             $elements[$j]->page_id  = $_rawElements[$elements[$j]->element_id]->page_id;
           }
           }
         }*/

      $this->elements = $rawElements;
    }

    return $this->elements;
  }

  public function getRows()
  {
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select(['*']);
    $query->from($db->quoteName('#__formea_form_rows'));
    if ($this->type == 0) {
      $query->where($db->quoteName('form_id') . ' = ' . $db->quote($this->form_id));
    } else {
      $query->where($db->quoteName('group_id') . ' = ' . $db->quote($this->group_id));
    }
    $query->where($db->quoteName('row_type') . ' = ' . $db->quote($this->type));
    if ($this->page_id > 0) {
      $query->where($db->quoteName('page_id') . ' = ' . $db->quote($this->page_id));
    }
    $query->order('id ASC');
    $db->setQuery($query);
    $_formRows = $db->loadObjectList();
    $formRows  = [];
    if (!empty($_formRows)) {
      $totalFormRows = count($_formRows);
      for ($i = 0; $i < $totalFormRows; $i++) {
        $formRows[$_formRows[$i]->id] = new FormeaGridItem([
          'formId'        => $this->form_id,
          'group_id'      => $this->group_id,
          'id'            => $_formRows[$i]->id,
          'item_type'     => 0,
          'items'         => [],
          'gutterX'       => $_formRows[$i]->gutterX,
          'gutterY'       => $_formRows[$i]->gutterX,
          'settings'      => $_formRows[$i]->settings,
          'nextColumnIdx' => 0, //TODO: determine next row
          'class'         => $_formRows[$i]->class,
          'styleSheet'    => $_formRows[$i]->styleSheet,
          'active'        => false,
        ], $this->settingRegistry);
      }
    }

    return $formRows;
  }

  public function getColumns()
  {
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_form_columns'));

    if ($this->type == 0) {
      $query->where($db->quoteName('form_id') . ' = ' . $db->quote($this->form_id));
    } else {
      $query->where($db->quoteName('group_id') . ' = ' . $db->quote($this->group_id));
    }
    $query->where($db->quoteName('column_type') . ' = ' . $db->quote($this->type));
    if ($this->page_id > 0) {
      $query->where($db->quoteName('page_id') . ' = ' . $db->quote($this->page_id));
    }
    $query->order('id ASC');
    $db->setQuery($query);
    $_columns = $db->loadObjectList();
    $columns  = [];
    if (!empty($_columns)) {
      $totalColumns = count($_columns);
      for ($i = 0; $i < $totalColumns; $i++) {
        $columns[$_columns[$i]->id] = new FormeaGridItem([
          'formId'     => $this->form_id,
          'group_id'   => $this->group_id,
          'id'         => $_columns[$i]->id,
          'item_type'  => 1,
          'items'      => [],
          'settings'   => $_columns[$i]->settings,
          'column'     => $_columns[$i]->column,
          'class'      => $_columns[$i]->class,
          'styleSheet' => $_columns[$i]->styleSheet,
          'active'     => false,
        ], $this->settingRegistry);
      }
    }

    return $columns;
  }

  public function getGridItem()
  {
    $elementClasses = $this->getElementClasses();
    $defaultSetting = FormeaGeneralHelper::getGeneralElementSettings();
    $db             = $this->db;
    $query          = $db->getQuery(true);
    $query->select(['a.*', 'b.value_type']);
    $query->from($db->quoteName('#__formea_form_elements', 'a'))->innerJoin(
      $db->quoteName('#__formea_eltypes', 'b') . ' ON ' . $db->quoteName('a.type') . ' = ' .
        $db->quoteName('b.name')
    );

    if ($this->type == 0) {
      $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($this->form_id));
    } else {
      $query->where($db->quoteName('a.group_id') . ' = ' . $db->quote($this->group_id));
    }
    $query->where($db->quoteName('a.target_type') . ' = ' . $db->quote($this->type));
    if ($this->page_id > 0) {
      $query->where($db->quoteName('a.page_id') . ' = ' . $db->quote($this->page_id));
    }

    $query->order('id ASC');
    $db->setQuery($query);
    $elements = $db->loadObjectList();
    $ret      = [];
    if (!empty($elements)) {
      $totalElements = count($elements);

      for ($i = 0; $i < $totalElements; $i++) {
        $elements[$i]->settings = new Registry($elements[$i]->settings);
        if (isset($elementClasses[$elements[$i]->element_id])) {
          $formeaElement = $elementClasses[$elements[$i]->element_id];
          $formeaElement->set('group_type', 0);
          $formeaElement->set('isGroup', $elements[$i]->group_id > 0);
          $formeaElement->set('group_id', $elements[$i]->group_id);
          $formeaElement->set('setIndex', $this->setIndex);
          $formeaElement->set('form_id', $this->form_id);
          $formeaElement->set('form_element_settings', $elements[$i]->settings);
          $formeaElement->setElementTypeClassParam('setIndex', $this->setIndex);
          $formeaElement->setElementTypeClassParam('group_type', 0);
          $formeaElement->setElementTypeClassParam('isGroup', $elements[$i]->group_id > 0);
          $formeaElement->setElementTypeClassParam('group_id', $elements[$i]->group_id);
          $formeaElement->setElementTypeClassParam('form_id', $this->form_id);
          $formeaElement->setElementTypeClassParam('form_element_settings', $elements[$i]->settings);
        } else {

          $formeaElement = new FormeaElement([
            'element_id'            => $elements[$i]->element_id,
            'form_id'               => $this->form_id,
            'isPreview'             => $this->isPreview,
            'formUniqueString'      => $this->formUniqueString,
            'isGroup'               => $this->group_id > 0,
            'group_id'              => $this->group_id,
            'group_type'            => 0,
            'setIndex'              => $this->setIndex,
            'coreClasses'           => $this->coreClasses,
            'form_element_settings' => $elements[$i]->settings,
          ]);
          $formeaElement->set('group_type', 0);
          $formeaElement->set('isGroup', $elements[$i]->group_id > 0);
          $formeaElement->set('group_id', $elements[$i]->group_id);
          $formeaElement->setElementTypeClassParam('group_type', 0);
          $formeaElement->setElementTypeClassParam('isGroup', $elements[$i]->group_id > 0);
          $formeaElement->setElementTypeClassParam('group_id', $elements[$i]->group_id);
          $formeaElement->setElementTypeClassParam('setIndex', $this->setIndex);
          $formeaElement->setElementTypeClassParam('form_element_settings', $elements[$i]->settings);
          $this->addElementClass($elements[$i]->element_id, $formeaElement);
        }
        $element = $formeaElement->getElement();
        /* if (!$this->isPreview && (int) $element->state != 1)
           {
             unset($elements[$i]);
             continue;
           }
           else
           {

           }*/


        if (empty($elements[$i]->labelSettings)) {
          $elements[$i]->labelSettings = [];
        } else {
          $elements[$i]->labelSettings = json_decode($elements[$i]->labelSettings);
        }
        if (!$this->isPreview) {
          $columnAttributes = [];
          if (!empty($elements[$i]->column_class)) {
            $columnAttributes['class'] = $elements[$i]->column_class;
          }

          if (!empty($this->themeClass)) {
            $formeaElement->set('themeClass', $this->themeClass);
          }
          $renderLabelSetting = FormeaGeneralHelper::formatKeyArray($elements[$i]->labelSettings, 'lang_code');
          $renderLabelSetting = new Registry($renderLabelSetting);

          $elements[$i]->input = $formeaElement->renderElement($columnAttributes, $renderLabelSetting);

          $elements[$i]->labelSettings = new Registry($elements[$i]->labelSettings);
        } else {
          $labelSetting                = $formeaElement->getLabelSettings();
          $elements[$i]->labelSettings = FormeaGeneralHelper::mapExistingLabelSetting($labelSetting, $elements[$i]->labelSettings);
        }

        // $elements[$i]->alias = str_replace('-', '_', $formeaElement->alias);
        $elements[$i]->alias = $formeaElement->alias;
        $styleSheet          = '';
        if (!empty($elements[$i]->settings)) {
          $defaultSetting         = $elements[$i]->settings;
          $elements[$i]->settings = json_decode($elements[$i]->settings);
        } else {
          $defaultSetting = json_encode($defaultSetting);
        }

        if (!empty($elements[$i]->styleSheet)) {
          $styleSheet = $elements[$i]->styleSheet;
        }
        $isGroup               = $elements[$i]->group_id > 0;
        $elements[$i]->isGroup = $elements[$i]->group_id > 0;
        $elements[$i]->state   = $formeaElement->state;
        if ($this->group_id > 0) {
          $isGroup               = true;
          $elements[$i]->isGroup = true;
        } else {
        }
        $elements[$i]->imageDetails = $element->getElementTypeImage(true);
        $formeaGridItem = new FormeaGridItem(
          [
            'formId'     => $elements[$i]->form_id,
            'id'         => $elements[$i]->id,
            'group_id'   => $elements[$i]->group_id,
            'isGroup'    => $isGroup,
            'item_type'  => 2,
            'active'     => false,
            'content'    => $elements[$i],
            'settings'   => $defaultSetting,
            'styleSheet' => $styleSheet,
            'state'      => $element->state
          ],
          $this->settingRegistry
        );

        $ret[$elements[$i]->id] = $formeaGridItem;
      }
    }

    return $ret;
  }

  public function getGrouped()
  {
    if (empty($this->rawGroups)) {
      $db    = $this->db;
      $query = $db->getQuery(true);
      $query->select(['a.*']);
      $query->from($db->quoteName('#__formea_form_groups', 'a'))->innerJoin(
        $db->quoteName('#__formea_groups', 'b') . ' ON ' . $db->quoteName('a.group_id') . ' = ' .
          $db->quoteName('b.id')
      );
      if ($this->type == 0) {
        $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($this->form_id));
      } else {
        $query->where($db->quoteName('a.group_id') . ' = ' . $db->quote($this->group_id));
      }
      $query->where($db->quoteName('a.group_type') . ' = ' . $db->quote($this->type));

      if ($this->page_id > 0) {
        $query->where($db->quoteName('a.page_id') . ' = ' . $db->quote($this->page_id));
      }
      //formea_form_elements
      $query->order('a.id ASC');
      $db->setQuery($query);
      $groups          = $db->loadObjectList();
      $this->rawGroups = $groups;
    }

    return $this->rawGroups;
  }

  /**
   * Elements that are in the form_group table
   *
   * @since version
   */
  public function getGroupedElements()
  {
    return $this->getGrouped();
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__user_profiles'));
    $query->where($db->quoteName('profile_key') . ' = ' . $db->quote('custom.%'));
    $query->order('ordering ASC');
    $db->setQuery($query);
    $results = $db->loadObjectList();

    return $results;
  }

  public function getGroupElements()
  {

    $_groupElements        = $this->getGrouped();
    $groupElements         = [];
    $groupedElementClasses = [];

    if (!empty($_groupElements)) {
      $totalGroupElements = count($_groupElements);
      $themeClass         = $this->getThemeClass();
      for ($i = 0; $i < $totalGroupElements; $i++) {
        $groupedElement = new FormeaGroupedElement($_groupElements[$i]->group_id, [
          'isPreview'    => $this->isPreview,
          'themeClass'   => $themeClass,
          'uniqueString' => $this->formUniqueString,
          'form_id'      => $this->form_id,
          'setIndex'     => 0
        ]);

        $this->addGroupElementClass($_groupElements[$i]->group_id, $groupedElement);
        $groupObject = $groupedElement->get();
        $items       = [];
        if ($groupedElement->group_type == 0) {
          //grid
          $items = $groupedElement->getLayout();
        }
        $groupElements[$_groupElements[$i]->id] = new FormeaGridItem([
          'id'             => $_groupElements[$i]->id,
          'group_id'       => $_groupElements[$i]->group_id,
          'isGroup'        => true,
          'item_type'      => 3,
          'settings'       => $groupObject->settings,
          'group_type'     => $groupObject->group_type,
          'inputGroupItem' => $groupedElement->getInputGroupParams(),
          'class'          => $groupObject->class,
          'styleSheet'     => $groupObject->styleSheet,
          'active'         => false,
          'items'          => $items,
          'form_id'        => $this->form_id,
          'state'          => $groupedElement->state,
          'content' => [
            'title' => $groupedElement->title
          ],
        ]);
      }
    }

    return $groupElements;
  }

  public function addGroupElementClass($key, $core)
  {
    $this->groupedElementClasses[$key] = $core;
  }

  public function getGroupElementClass()
  {
    return $this->groupedElementClasses;
  }


  public function getElementClasses()
  {
    if (empty($this->elementClasses)) {
      $ret           = [];
      $elements      = $this->getElements();
      $totalElements = count($elements);
      for ($i = 0; $i < $totalElements; $i++) {
        $ret[$elements[$i]->element_id] = new FormeaElement([
          'element_id'       => $elements[$i]->element_id,
          'form_id'          => $this->form_id,
          'isPreview'        => $this->isPreview,
          'formUniqueString' => $this->formUniqueString,
          'isGroup'          => $this->group_id > 0,
          'group_id'         => $this->group_id,
          'group_type'       => 0,
          'coreClasses'      => $this->coreClasses,
          'themeClass'       => $this->themeClass
        ]);
      }
      $this->elementClasses = $ret;
    }

    return $this->elementClasses;
  }

  public function getThemeClass()
  {
    return $this->themeClass;
  }

  public function addElementClass($element_id, $formeaElement)
  {
    $this->elementClasses[$element_id] = $formeaElement;
  }

  public function set($key, $value)
  {
    $this->{$key} = $value;
  }

  public function getSingleGroupElement($group_id, $setIndex)
  {
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select(['a.*']);
    $query->from($db->quoteName('#__formea_form_groups', 'a'));
    if ($this->type == 0) {
      $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($this->form_id));
    } else {
      $query->where($db->quoteName('a.group_id') . ' = ' . $db->quote($this->group_id));
    }
    $query->where($db->quoteName('a.group_type') . ' = ' . $db->quote($this->type));

    if ($this->page_id > 0) {
      $query->where($db->quoteName('a.page_id') . ' = ' . $db->quote($this->page_id));
    }
    $db->setQuery($query);
    $groups         = $db->loadObject();
    $themeClass     = $this->getThemeClass();
    $groupedElement = new FormeaGroupedElement($group_id, [
      'isPreview'    => $this->isPreview,
      'themeClass'   => $themeClass,
      'uniqueString' => $this->formUniqueString,
      'form_id'      => $this->form_id,
      'setIndex'     => $setIndex
    ]);

    $this->addGroupElementClass($group_id, $groupedElement);
    $groupObject = $groupedElement->get();
    $items       = [];
    if ($groupedElement->group_type == 0) {
      //grid
      $items = $groupedElement->getLayout();
    }
    $groupElement = new FormeaGridItem([
      'id'             => $groups->id,
      'group_id'       => $group_id,
      'isGroup'        => true,
      'item_type'      => 3,
      'settings'       => $groupObject->settings,
      'group_type'     => $groupObject->group_type,
      'inputGroupItem' => $groupedElement->getInputGroupParams(),
      'class'          => $groupObject->class,
      'styleSheet'     => $groupObject->styleSheet,
      'active'         => false,
      'items'          => $items,
      'form_id'        => $this->form_id,
      'state'          => $groupedElement->state
    ]);

    return [
      'groupElement'        => $groupElement,
      'groupedElementClass' => $groupedElement
    ];
  }
}
