<?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 Exception;
use Feseur\Library\FsrHelper;
use Feseur\Library\FsrResponse;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseDriver;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;

class FormeaGroupedElement
{
  public $id;
  public $title;
  public $alias;
  public $class;
  public $state;
  public $inline_css;
  public $additional_css;
  public $inline_js;
  public $additional_js;
  public $group_type;
  public $labelSettings;
  public $settings;
  public $styleSheet;
  public $access_level;
  public $params;
  public $layout;
  public $elements;
  protected $isSet;
  /**
   * @var DatabaseDriver
   * @since 1.0.0
   */
  protected $db;

  /**
   * @var FormeaGridOperations | null
   * @since 1.0.3
   */
  protected $gridOperation = null;

  /**
   * @var boolean
   * @since version
   */
  protected $isPreview;

  protected $uniqueString;

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

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

  /**
   * @var array | null
   * @since 1.0.0
   */
  protected $inputGroupElements = null;

  public $setIndex = 0;

  /**
   * @var int
   * @since 1.0.0
   */
  protected $form_id = 0;

  /**
   * @var FormeaCore[]
   * @since 1.0.3
   */
  public $groupCores = [];


  public function __construct($groupedElementId, $config = [])
  {
    $isPreview = false;
    $this->id  = $groupedElementId;
    $container = Factory::getContainer();
    $this->db  = $container->get('DatabaseDriver');
    if (isset($config['isPreview'])) {
      $isPreview = $config['isPreview'];
    }
    if (isset($config['themeClass'])) {
      $this->themeClass = $config['themeClass'];
    } else {
      $this->themeClass = new FormeaTheme();
    }
    if (isset($config['uniqueString'])) {
      $this->uniqueString = $config['uniqueString'];
    }
    if (isset($config['setIndex'])) {
      $this->setIndex = $config['setIndex'];
    }

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

    $this->isPreview = $isPreview;
  }

  public function getGridOperation()
  {
    if (empty($this->gridOperation)) {
      $this->gridOperation = new FormeaGridOperations($this->id, 1, [
        'isPreview'        => $this->isPreview,
        'formUniqueString' => $this->getUniqueString(),
        'form_id'          => $this->form_id,
        'setIndex'         => $this->setIndex,
        'themeClass'       => $this->getThemeClass(),
      ]);
    }

    return $this->gridOperation;
  }

  public function getElementClasses($whereClause = [])
  {
    $operators = $this->getGridOperation();

    return $operators->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->getUniqueString(),
          'isGroup'          => true,
          'group_id'         => $this->id,
          'group_type'       => $this->group_type
        ]);
        }
        $this->elementClasses = $ret;
      }

      return $this->elementClasses;*/
  }

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

  public function get()
  {
    if (!$this->isSet) {
      $container = Factory::getContainer();
      /** @var DatabaseDriver $db */
      $db    = $container->get('DatabaseDriver');
      $query = $db->getQuery(true);
      $query->select('*');
      $query->from($db->quoteName('#__formea_groups'));
      $query->where($db->quoteName('id') . ' = ' . $db->quote($this->id));
      if (!$this->isPreview) {
        $query->where($db->quoteName('state') . ' = ' . $db->quote(1));
      }
      $db->setQuery($query);
      $result = $db->loadObject();
      if (!empty($result)) {
        $result->labelSettings = json_decode($result->labelSettings);
        $result->settings      = json_decode($result->settings);
        $result->layout        = json_decode($result->layout);
        foreach ($result as $key => $value) {
          $this->set($key, $value);
        }

        //get core
        $query->clear();
        $query->select('*');
        $query->from($db->quoteName('#__formea_group_cores'));
        $query->where($db->quoteName('group_id') . ' = ' . $db->quote($this->id));
        $query->where($db->quoteName('enabled') . ' = ' . $db->quote(1));
        $db->setQuery($query);
        $_cores = $db->loadObjectList();
        if (!empty($_cores)) {
          $_totalCores = count($_cores);
          for ($i = 0; $i < $_totalCores; $i++) {

            if (is_file(Path::clean(FORMEA_CORE_PATH . '/' . $_cores[$i]->corename . '/Formea' . $_cores[$i]->corename . '.php'))) {
              $_coreClassName = 'Formea' . $_cores[$i]->corename;
              require_once FORMEA_CORE_PATH . '/' . $_cores[$i]->corename . '/Formea' . $_cores[$i]->corename . '.php';
              $_config = [
                'formUniqueString' => $this->uniqueString,
                'formId'           => $this->form_id,
                'group_id'         => $this->id,
                'id'               => $_cores[$i]->id,
              ];
              if (!empty($_cores[$i]->params)) {
                $_config['formParams'] = new Registry($_cores[$i]->params);
              }
              $__core                            = new $_coreClassName($_config);
              $this->groupCores[$_cores[$i]->id] = $__core;
            }
          }
        }

        $this->isSet = true;
      }
    }

    return $this;
  }

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

      return true;
    }

    return false;
  }

  public function getLayout()
  {
    //get all rows
    $rows           = $this->getRows();
    $columns        = $this->getColumns();
    $gridItems      = $this->getElementGridItem();
    $childGroups    = $this->getChildGroup();
    $groupedElement = $this->get();
    $layout         = $groupedElement->layout;
    $structure      = $this->_assignLayout($layout, $rows, $columns, $gridItems, $childGroups);

    return $structure;
  }

  protected function _assignLayout($items, $rows, $columns, $gridItems, $childGroups)
  {
    $structure = [];
    if (!is_null($items)) {
      $totalItems = count($items);
      for ($i = 0; $i < $totalItems; $i++) {
        if ($items[$i]->item_type == 0) {
          //check rows
          if (isset($rows[$items[$i]->item_id])) {
            $structure[$i] = $rows[$items[$i]->item_id];
          }
        } else if ($items[$i]->item_type == 1) {
          //columns
          if (isset($columns[$items[$i]->item_id])) {
            $structure[$i] = $columns[$items[$i]->item_id];
          }
        } else if ($items[$i]->item_type == 2) {
          //element
          if (isset($gridItems[$items[$i]->item_id])) {
            $structure[$i] = $gridItems[$items[$i]->item_id];
          }
        } else {
          //group
        }

        if (!empty($items[$i]->items)) {
          $structure[$i]->items = $this->_assignLayout($items[$i]->items, $rows, $columns, $gridItems, $childGroups);
        }
      }
    }


    return $structure;
  }

  public function getRows()
  {
    return ($this->getGridOperation())->getRows();
  }

  public function getColumns()
  {
    return ($this->getGridOperation())->getColumns();
  }

  public function getElements()
  {
    return ($this->getGridOperation())->getElements();
  }

  public function getElementGridItem()
  {
    $operations = $this->getGridOperation();
    $operations->set('form_id', $this->form_id);
    $this->elements = $operations->getGridItem();

    return $this->elements;
  }

  public function getChildGroup()
  {
    return ($this->getGridOperation())->getGroupElements();
  }

  public function getDefaultfFields()
  {
    return [
      'id',
      'title',
      'alias',
      'class',
      'state',
      'inline_css',
      'additional_css',
      'inline_js',
      'additional_js',
      'group_type',
      'labelSettings',
      'settings',
      'styleSheet',
      'access_level',
      'params',
      'layout',
    ];
  }

  public function delete()
  {
    $retObject = new FsrResponse();
    try {
      $formLayouts = $this->getFormsRelatedToGroup();

      $db                = $this->db;
      $query             = $db->getQuery(true);
      $targetTables      = [
        ['table' => 'formea_form_rows', 'key' => 'row_type'],
        ['table' => 'formea_form_columns', 'key' => 'column_type'],
        ['table' => 'formea_form_elements', 'key' => 'target_type'],
        ['table' => 'formea_form_groups', 'key' => 'group_type'],
        ['table' => 'formea_group_cores', 'key' => null],
      ];
      $totalTargetTables = count($targetTables);
      for ($j = 0; $j < $totalTargetTables; $j++) {
        //TODO:handle the group that are applied to the form, rebuild the layout


        $conditions = array(
          $db->quoteName('group_id') . ' = ' . $this->id,
        );
        if (!empty($targetTables[$j]['key'])) {
          $conditions[] = $db->quoteName($targetTables[$j]['key']) . ' = 1';
        }

        $query->clear();
        $query->delete($db->quoteName('#__' . $targetTables[$j]['table']));
        $query->where($conditions);
        $db->setQuery($query);
        $db->execute();
      }
      $query->clear();
      $conditions = array(
        $db->quoteName('id') . ' = ' . $this->id
      );
      $query->delete($db->quoteName('#__formea_groups'));
      $query->where($conditions);
      $db->setQuery($query);
      $db->execute();

      //resetformlayout
      $totalForms = count($formLayouts);
      for ($i = 0; $i < $totalForms; $i++) {
        $layouts      = $formLayouts[$i]->layouts;
        $totalLayouts = count($layouts);
        for ($k = 0; $k < $totalLayouts; $k++) {
          $jsonData = $layouts[$k]->layout;
          $data     = json_decode($jsonData, true);
          $this->removeItemFromArray($data, 3, $formLayouts[$i]->form_group_id);
          $upd = [
            'id'     => $layouts[$k]->id,
            'layout' => json_encode($data)
          ];
          $upd = (object) $upd;
          $this->db->updateObject('#__formea_form_fieldsets', $upd, 'id');
        }
      }

      $retObject->setSuccess(true);
    } catch (Exception $e) {
      $retObject->setMsg($e->getMessage());
    }

    return $retObject;
  }

  protected function getFormsRelatedToGroup()
  {
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select(['a.form_id', 'a.id AS form_group_id']);
    $query->from($db->quoteName('#__formea_form_groups', 'a'));
    $query->where($db->quoteName('a.group_id') . ' = ' . $db->quote($this->id));
    $query->where($db->quoteName('a.group_type') . ' = ' . $db->quote(0));
    $db->setQuery($query);
    $formIds = $db->loadObjectList();
    if (!empty($formIds)) {
      $totalFormIds = count($formIds);
      for ($i = 0; $i < $totalFormIds; $i++) {
        $query->clear();
        $query->select(['a.layout', 'a.id']);
        $query->from($db->quoteName('#__formea_form_fieldsets', 'a'));
        $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($formIds[$i]->form_id));
        $db->setQuery($query);
        $layouts              = $db->loadObjectList();
        $formIds[$i]->layouts = $layouts;
      }
    }

    return $formIds;
    //formea_form_fieldsets
  }

  protected function removeItemFromArray(&$array, $itemType, $itemId)
  {
    foreach ($array as $key => &$value) {
      if (is_array($value)) {
        if (isset($value["item_type"]) && $value["item_type"] == $itemType && isset($value["item_id"]) && $value["item_id"] == $itemId) {
          // Check if 'item_type' and 'item_id' match, then unset the current item
          unset($array[$key]);
        } else {
          // Recursively call the function for nested "items" arrays
          $this->removeItemFromArray($value["items"], $itemType, $itemId);
        }
      }
    }
  }

  public function getUniqueString()
  {
    if (empty($this->uniqueString)) {
      $this->uniqueString = FsrHelper::generateRandomUniqueString(8);
    }

    return $this->uniqueString;
  }

  public function getPreview()
  {
    $this->get();
    $themeClass    = $this->getThemeClass();
    $labelSettings = $this->labelSettings;
    $previews      = [];
    $errorMsg      = [];
    if (!empty($labelSettings)) {
      $totalLabel = count($labelSettings);

      for ($j = 0; $j < $totalLabel; $j++) {
        $container          = $themeClass->drawInputGroupContainer($this->id);
        $inputGroupElements = $this->getInputGroupElements();
        $elementClasses     = $this->getElementClasses();
        $totalElements      = count($inputGroupElements);
        $elementHtml        = '';
        $_errorMsg          = [];
        for ($i = 0; $i < $totalElements; $i++) {
          if (isset($elementClasses[$inputGroupElements[$i]->element_id])) {
            $elementClasses[$inputGroupElements[$i]->element_id]->set('group_type', 1);
            $elementClasses[$inputGroupElements[$i]->element_id]->set('isPreview', $this->isPreview);
            $elementClasses[$inputGroupElements[$i]->element_id]->set('setIndex', $this->setIndex);
            $elementClasses[$inputGroupElements[$i]->element_id]->setElementTypeClassParam('group_type', 1);
            $elementClasses[$inputGroupElements[$i]->element_id]->setElementTypeClassParam('setIndex', $this->setIndex);
            $elementHtml   .= $elementClasses[$inputGroupElements[$i]->element_id]->renderInputGroup($labelSettings[$j]);

            $hasError      = false;
            $feedbackClass = ['fm_feedback_el'];
            $__errorMsg    = $elementClasses[$inputGroupElements[$i]->element_id]->getErrorMsg();
            $___errorMsg   = '';
            if (!empty($__errorMsg)) {
              $hasError    = true;
              $_errorMsg   = $__errorMsg;
              $___errorMsg = implode('<br/>', $__errorMsg);
            }

            $feedbackClass[] = $themeClass->getFeedbackContainerClass(true);
            $elementHtml     .= '<div class="' . implode(' ', $feedbackClass) . '">' . $___errorMsg . '</div>';
          }
        }
        $container                               = str_replace('[ELEMENT_LISTS_' . $this->id . ']', $elementHtml, $container);
        $previews[$labelSettings[$j]->lang_code] = $container;
        $errorMsg[$labelSettings[$j]->lang_code] = $_errorMsg;
      }
    }


    return [
      'previews' => $previews,
      'errorMsg' => $errorMsg
    ];
  }

  public function getInputGroupElements()
  {
    if (is_null($this->inputGroupElements)) {
      $this->get();
      $__elements         = $this->getElementGridItem();
      $__elements         = array_values($__elements);
      $inputGroupElements = [];
      foreach ($__elements as $el) {
        $inputGroupElements[] = $el->content;
      }
      $this->inputGroupElements = $inputGroupElements;
    }

    return $this->inputGroupElements;
  }


  public function getInputGroupParams()
  {
    $this->get();
    $inputGroupElements = $this->getInputGroupElements();
    $_previews          = $this->getPreview();
    $previews           = $_previews['previews'];
    $errorMsg           = $_previews['errorMsg'];
    $rows               = $this->getLayout();
    $ret                = [
      'group_id'            => $this->id,
      'group_type'          => $this->group_type,
      'class'               => $this->class,
      'settings'            => $this->settings,
      'content' => [
        'title' => $this->title
      ],
      'labelSettings'       => $this->labelSettings,
      'elements'            => $inputGroupElements,
      'elementsPreview'     => $previews,
      'errorMsg'            => $errorMsg,
      'elementsPreviewSafe' => $previews,
      'styleSheet'          => $this->styleSheet,
      'igSetting'           => [
        'bare' => false
      ],
      'rows'                => $rows
    ];
    return $ret;
  }

  public function refactorGroupBlock($htmlStructure, $groupedElement)
  {
    $this->get();
    $groupCores = $this->groupCores;
    if (!empty($groupCores)) {
      $groupCores      = array_values($groupCores);
      $totalGroupCores = count($groupCores);
      for ($i = 0; $i < $totalGroupCores; $i++) {
        $htmlStructure = $groupCores[$i]->refactorGroupBlock($htmlStructure, $groupedElement);
      }
    }

    return $htmlStructure;
  }
}
