<?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\FsrResponse;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Factory;
use Joomla\Filesystem\Folder;
use Joomla\CMS\Language\Text;
use Joomla\Component\Formea\Site\Helper\FormeaGeneralHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;

class FormeaTheme
{
  /**
   * @var string
   * @since 1.0.0
   */
  public $langTag;

  /**
   * @var string
   * @since 1.0.0
   */
  public $langTagUnderScore;

  /**
   * @var string[]
   * @since 1.0.0
   */
  public $labelElementClass = [];

  /**
   * @var string[]
   * @since 1.0.0
   */
  public $labelInlineElementClass = [];

  /**
   * @var FormeaEltype[]
   * @since 1.0.0
   */
  public $elementTypeClass = [];

  /**
   * @var string
   * @since 1.0.0
   */
  protected $rowClass;

  /**
   * @var string
   * @since 1.0.0
   */
  protected $colClass;

  /**
   * @var FormeaCore
   * @since 1.0.0
   */
  protected $renderer;

  /**
   * @var CMSApplicationInterface
   * @since 1.0.0
   */
  protected $app;

  /**
   * @var string
   * @since 1.0.0
   */
  private $formUniqueString;

  /**
   * @var int
   * @since 1.0.0
   */
  public $id = 0;

  /**
   * @var int
   * @since 1.0.0
   */
  public $style_id = 0;

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

  protected $form_id = 0;

  public function __construct($config = [])
  {
    if (isset($config['id'])) {
      $this->id = $config['id'];
    }
    if (isset($config['style_id'])) {
      $this->style_id = $config['style_id'];
    }
    if (isset($config['renderer'])) {
      $this->renderer = $config['renderer'];
    } else {
      $this->renderer = new FormeaCore([]);
    }
    if (isset($config['formUniqueString'])) {
      $this->formUniqueString = $config['formUniqueString'];
    }

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

    $this->app = Factory::getApplication();
    if (isset($config['langTag'])) {
      $this->langTag = $config['langTag'];
    } else {
      $this->langTag = $this->app->getLanguage()->getTag();
    }
    if (isset($config['langTagUnderScore'])) {
      $this->langTagUnderScore = $config['langTagUnderScore'];
    } else {
      $this->langTagUnderScore = str_replace('-', '_', $this->langTag);
    }

    $this->labelElementClass       = [
      'form-label'
    ];
    $this->labelInlineElementClass = [
      'col-form-label'
    ];
    $this->elementTypeClass        = [
      'input'    => 'form-control',
      'select'   => 'form-select',
      'textarea' => 'form-control',
      'radio'    => 'form-check-input',
      'checkbox' => 'form-check-input',
      'button'   => 'btn'
    ];

    $this->rowClass = 'row';
    $this->colClass = 'col';
  }

  /**
   * @param   FormeaCore  $renderer
   *
   *
   * @since 1.0.0
   */
  public function setRenderer($renderer)
  {
    $this->renderer = $renderer;
  }

  /**
   * Classes to be used on <label> element
   * @return array
   *
   * @since 1.0.0
   */
  public function getLabelElClass()
  {
    return $this->labelElementClass;
  }

  /**
   * CSS classes to be used for label that has column. eg:col-form-label
   * @return array
   *
   * @since 1.0.0
   */
  public function getLabelInlineElClass()
  {
    return $this->labelInlineElementClass;
  }

  public function getFeedbackPageClass($error = false)
  {
    if ($error) {
      return 'text-danger';
    } else {
      return '';
    }
  }

  /**
   * @param $page
   * @param $currentIdx
   * @param $totalPages
   *
   * @return string
   *
   * @since version
   */
  public function drawPage($formId, $page, $currentIdx, $totalPages)
  {
    $pageAttributes    = [];
    $pageClass         = ['fm_page_' . $page->id];
    $pageFeedbackClass = ['fm_page_feedback_' . $page->id];
    if (!empty($this->renderer)) {
      $rendererParams = $this->renderer->drawPageElementAttribute($formId, $currentIdx, $totalPages);
      if (isset($rendererParams['pageAttributes'])) {
        if (!empty($rendererParams['pageAttributes'])) {
          $pageAttributes = array_merge($rendererParams['pageAttributes'], $pageAttributes);
        }
      }
      if (isset($rendererParams['pageClass'])) {
        if (!empty($rendererParams['pageClass'])) {
          $pageClass = array_merge($rendererParams['pageClass'], $pageClass);
        }
      }
      if (isset($rendererParams['pageFeedbackClass'])) {
        if (!empty($rendererParams['pageFeedbackClass'])) {
          $pageFeedbackClass = array_merge($rendererParams['pageFeedbackClass'], $pageFeedbackClass);
        }
      }
    }
    $themeFeedbackClass = $this->getFeedbackPageClass();
    if (!empty($themeFeedbackClass)) {
      $pageFeedbackClass[] = $themeFeedbackClass;
    }
    $html = '<div class="' . implode(' ', $pageClass) . '"';
    foreach ($pageAttributes as $attr => $val) {
      $html .= ' ' . $attr . '="' . $val . '"';
    }
    $html .= ' >';
    $html .= '[LAYOUT_' . $page->id . ']';
    $html .= '<div class="' . implode(' ', $pageFeedbackClass) . '"></div>';
    $html .= '</div>';

    return $html;
  }

  /**
   * CSS class for an outer flex block. eg:row
   * @return string
   *
   * @since 1.0.0.
   */
  public function getRowClass()
  {
    return $this->rowClass;
  }

  public function drawRow($page, $row)
  {

    $blockClass = ['fm_row_' . $page->form_id . '_' . $row->id];
    $rowClass   = [$this->rowClass];
    if (!empty($row->class)) {
      $rowClass[] = $row->class;
    }

    if (isset($row->gutterX)) {
      if ((int) $row->gutterX > -1) {
        $rowClass[] = 'gx-' . $row->gutterX;
      }
    }

    if (isset($row->gutterY)) {
      if ((int) $row->gutterY > -1) {
        $rowClass[] = 'gy-' . $row->gutterY;
      }
    }

    $html = '<div class="' . implode(' ', $blockClass) . '">';
    $html .= '<div class="' . implode(' ', $rowClass) . '">[COLUMN_' . $page->id . '_' . $row->id . ']</div>';
    $html .= '</div>';

    return $html;
  }

  public function drawColumn($page, $column)
  {
    $html                 = '';
    $columnContainerClass = ['fm_column_' . $page->form_id . '_' . $column->id];
    $html                 .= '<div class="' . $this->getColumnClass($column->column) . '">';
    $html                 .= '<div class="' . implode(' ', $columnContainerClass) . '">';
    $html                 .= '[ITEM_' . $page->id . '_' . $column->id . ']';
    $html                 .= '</div>';
    $html                 .= '</div>';

    return $html;
  }

  /**
   * @param                   $page
   * @param   FormeaGridItem  $item
   * @param                   $isLast
   *
   * @return mixed
   *
   * @since 1.0.0
   */
  public function drawItem($page, $item, $isLast = false)
  {
    return $item->content->input;
  }


  /**
   * @param                         $page
   * @param   FormeaGridItem        $item
   * @param   FormeaGroupedElement  $groupedElementClass
   *
   * @return string
   *
   * @since version
   */
  public function drawGroupBlock($form_id, $page, $item, $groupedElementClass)
  {

    if (!empty($groupedElementClass)) {
      $groupedElement = $groupedElementClass;
    } else {
      $groupedElement = new FormeaGroupedElement($item->group_id, [
        'form_id'      => $form_id,
        'uniqueString' => $this->formUniqueString,
        'themeClass'   => $this,
      ]);
      $groupedElement->get();
    }
    $_lblsetting  = $groupedElement->labelSettings;
    $labelSetting = [];
    $totalLbl     = count($_lblsetting);
    for ($i = 0; $i < $totalLbl; $i++) {
      if ($_lblsetting[$i]->lang_code === $this->langTagUnderScore) {
        $labelSetting = $_lblsetting[$i];
        break;
      }
    }
    $labelSetting = new Registry($labelSetting);

    $labelText          = $labelSetting->get('caption', '');
    $labelClass         = $this->getLabelElClass();
    $inputWrapper       = '';
    $inputWrapperCloser = '';

    $labelPosition   = $labelSetting->get('setting.position', 'TOP');
    $helperTextAlign = $labelSetting->get('helper_align', 'LEFT');
    $showLabel       = filter_var($labelSetting->get('setting.show_label', false), FILTER_VALIDATE_BOOLEAN);

    if (!empty($labelSetting)) {
      $labelPosition     = strtoupper($labelSetting->get('setting.position', 'TOP'));
      $labelSettingAlign = strtoupper($labelSetting->get('setting.align', 'LEFT'));
      $showLabel         = filter_var($labelSetting->get('setting.show_label', 'true'), FILTER_VALIDATE_BOOLEAN);
      if ($showLabel) {
        if ($labelPosition !== 'TOP') {
          $labelColumn           = (int) $labelSetting->get('setting.label_column', 12);
          $columnClass[]         = $this->getRowClass();
          $labelClass            = array_merge($this->getLabelInlineElClass(), $labelClass);
          $labelClass[]          = $this->getColumnClass($labelColumn);
          $wrapperSize           = $this->getColumnAutoClass();
          $wrapperCalculatedSize = 12 - $labelColumn;
          if ($wrapperCalculatedSize > 0) {
            $wrapperSize = $this->getColumnClass($wrapperCalculatedSize);
          }
          $inputWrapper       = '<div class="' . $wrapperSize . '">';
          $inputWrapperCloser = '</div>';
        }
        $labelClass[] = $this->getTextAlignClass($labelSettingAlign);
      }
    }

    if ($labelPosition === 'TOP') {
      $columnClass[] = $this->getBlockClass();
    }

    if (isset($columnAttributes['class'])) {
      $columnClass[] = $columnAttributes['class'];
    }

    $body = '<div class="' . implode(' ', $columnClass) . '">';
    if ($labelPosition !== 'RIGHT' && $showLabel) {
      $body .= $this->getLabel($labelText, $labelClass);
    }

    $_body = '[BLOCK_ITEM_' . $page->id . '_' . $item->id . ']';

    $body .= $inputWrapper;
    $body .= $_body;
    $body .= $inputWrapperCloser;

    if ($labelPosition === 'RIGHT' && $showLabel) {
      $body .= $this->getLabel($labelText, $labelClass);
    }
    $body .= '</div>';


    $coreClasses   = $this->coreClasses;
    $divAttributes = [];
    if (!empty($coreClasses)) {
      $coreClasses      = array_values($coreClasses);
      $totalCoreClasses = count($coreClasses);
      for ($j = 0; $j < $totalCoreClasses; $j++) {
        $divAttributes = array_merge($coreClasses[$j]->getInputGroupContainerAttributes($item), $divAttributes);
      }
    }

    $opening = '<div class="fm_grouped_element_' . $form_id . '_' . $item->group_id . '"';
    foreach ($divAttributes as $attr => $attrVal) {
      $opening .= ' ' . $attr . '="' . $attrVal . '" ';
    }
    $opening .= '>';


    $closing = '</div>';

    $htmlStructure = [
      'opening' => $opening,
      'body'    => $body,
      'closing' => $closing
    ];
    $htmlStructure = $groupedElement->refactorGroupBlock($htmlStructure, $groupedElement);
    $htmlStructure = array_values($htmlStructure);

    return implode('', $htmlStructure);
  }


  /**
   * The css class for column by 12 grid system
   *
   * @param   int     $column  based on the 12 Grid system
   * @param   string  $screen  the responsive suffix. Eg: 'sm'|'md'|'lg'
   *
   * @return string
   *
   * @since 1.0.0
   */
  public function getColumnClass($column, $screen = 'md')
  {
    return $this->colClass . '-' . $screen . '-' . $column;
  }

  /**
   *
   * @return string
   *
   * @since 1.0.0
   */
  public function getColumnAutoClass()
  {
    return $this->colClass . '-auto';
  }

  public function getTextAlignClass($position = 'TOP')
  {
    $ret = '';
    switch (strtoupper($position)) {
      case 'RIGHT':
        $ret = 'text-end';
        break;
      case 'CENTER':
        $ret = 'text-center';
      default:
        $ret = 'text-start';
    }

    return $ret;
    /*return match (strtoupper($position))
			{
				'RIGHT' => 'text-end',
				'CENTER' => 'text-center',
				default => 'text-start',
			};*/
  }

  /**
   *
   * @return string
   *
   * @since 1.0.5
   */
  public function getFormGroupClass()
  {
    return '';
  }

  public function getBlockClass()
  {
    return 'd-block';
  }

  public function getContainerClass($isError = false)
  {
    return '';
  }

  public function getErrorClass()
  {
    return 'is-invalid';
  }

  public function getNoErrorClass()
  {
    return 'is-valid';
  }

  public function getInputClass($type = 'input')
  {
    if (isset($this->elementTypeClass[$type])) {
      return $this->elementTypeClass[$type];
    } else {
      return '';
    }
  }

  public function getFeedbackContainerClass($error = true)
  {
    if ($error) {
      return 'invalid-feedback';
    } else {
      return 'valid-feedback';
    }
  }

  public function getHelperTextContainerClass()
  {
    return 'form-text ';
  }

  public function getRadioContainerClass($param = [])
  {
    $layout = 'stacked';
    $str    = ['form-check'];
    if (isset($param['layout'])) {
      $layout = $param['layout'];
    }
    switch ($layout) {
      case 'inline':
        $str[] = 'form-check-inline';
        break;
      case 'stacked_reverse':
        $str[] = 'form-check-reverse';
        break;
      case 'inline_reverse':
        $str[] = 'form-check-inline';
        $str[] = 'form-check-reverse';
        break;
      default;
    }

    return implode(' ', $str);
  }

  public function getRadioLabelClass($param = [])
  {
    return 'form-check-label';
  }

  public function getButtonTypeElementClass($param = [])
  {
    $input_type = 'submit';
    if (isset($param['input_type'])) {
      $input_type = $param['input_type'];
    }
    if ($input_type !== 'submit') {
      return '';
    } else {
      return 'btn-primary';
    }
  }


  /**
   * Get the inline JS script to be pushed in the header
   *
   * @since 1.0.0
   */
  public function getGeneratedScript()
  {
    return '';
  }

  /**
   * Get the inline CSS to be pushed in the header
   *
   * @since 1.0.0
   */
  public function getGeneratedStyle()
  {
    return '';
  }

  /**
   * JS file list to load
   *
   * @since 1.0.0
   */
  public function getLoadableScript()
  {
    return [];
  }

  /**
   * CSS file list to load
   *
   * @since 1.0.0
   */
  public function getLoadableStyle()
  {
    return [];
  }

  public function drawInputGroupContainer($group_id)
  {
    $class = ['gp_fm_' . $group_id, 'has-validation'];
    $html  = '<div class="input-group ' . implode(' ', $class) . '">[ELEMENT_LISTS_' . $group_id . ']';
    $html  .= '</div>';

    return $html;
  }

  public function getInputGroupText()
  {
    return 'input-group-text';
  }

  /**
   * @param   FormeaGridItem        $gridItem
   * @param   string                $langTagUnderScore
   * @param   FormeaGroupedElement  $groupedElementClass
   *
   *
   * @since 1.0.0
   */
  public function renderInputGroupField($page, $gridItem, $langTagUnderScore, $groupedElementClass)
  {

    $inputGroupContainer = $this->drawInputGroupContainer($gridItem->group_id);
    $els                 = $gridItem->inputGroupItem['elementsPreview'];
    $langTagUnderScore   = str_replace('-', '_', $langTagUnderScore);
    if (isset($els[$langTagUnderScore])) {
      $inputGroupContainer = $els[$langTagUnderScore];
    }

    return $inputGroupContainer;
  }

  public function getLabel($label = 'label', $class = [])
  {
    return '<label class="' . implode(' ', $class) . '">' . $label . '</label>';
  }


  public function getThemeObject()
  {
    $container = Factory::getContainer();
    /** @var DatabaseDriver $db */
    $db    = $container->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_themes'));
    $query->where($db->quoteName('id') . ' = ' . $db->quote($this->id));
    $db->setQuery($query);

    return $db->loadObject();
  }

  /**
   * Method to delete Element type plugin (eltype)
   * @return FsrResponse
   *
   * @since 1.0.0
   */
  public function deleteThemePlugin()
  {
    $retObject = new FsrResponse();
    try {
      if ((int) $this->id < 1) {
        throw new Exception(Text::_('COM_FORMEA_NO_THEME_SELECTED'));
      }

      $container = Factory::getContainer();
      /** @var DatabaseDriver $db */
      $db    = $container->get('DatabaseDriver');
      $query = $db->getQuery(true);

      //check if element is in used
      $query->select(['a.title', 'a.name', 'b.theme_id', 'c.title AS form_title']);
      $query->from($db->quoteName('#__formea_themes', 'a'))->innerJoin(
        $db->quoteName('#__formea_formthemes', 'b') . ' ON ' . $db->quoteName('a.id') . ' = ' .
          $db->quoteName('b.theme_id')
      )->innerJoin(
        $db->quoteName('#__formea_forms', 'c') . ' ON ' . $db->quoteName('b.form_id') . ' = ' .
          $db->quoteName('c.id')
      );
      $query->where($db->quoteName('a.id') . ' = ' . $db->quote($this->id));
      $db->setQuery($query);
      $usedInFormLists = $db->loadObjectList();
      $themeObject     = $this->getThemeObject();
      if (empty($themeObject)) {
        throw new Exception(Text::_('COM_FORMEA_NO_THEME_FOUND'));
      }

      if (!empty($usedInFormLists)) {
        $eltype_title    = '';
        $formLists       = [];
        $totalUsedInForm = count($usedInFormLists);
        for ($i = 0; $i < $totalUsedInForm; $i++) {
          $eltype_title = $usedInFormLists[$i]->title;
          $formLists[]  = $usedInFormLists[$i]->form_title;
        }
        $msg = Text::sprintf('COM_FORMEA_FAILED_TO_DELETE_THEME_S', $eltype_title, implode(', ', $formLists));
        throw new Exception($msg);
      }

      // delete all custom keys for user 1001.
      $conditions = array(
        $db->quoteName('id') . ' = ' . $this->id
      );

      $query->clear();
      $query->delete($db->quoteName('#__formea_themes'));
      $query->where($conditions);
      $db->setQuery($query);
      $db->execute();

      $conditions = array(
        $db->quoteName('extension_id') . ' = ' . $this->id,
        $db->quoteName('extension_type') . ' = 1',
      );

      $query->clear();
      $query->delete($db->quoteName('#__formea_extension_styles'));
      $query->where($conditions);
      $db->setQuery($query);
      $db->execute();

      if (is_dir(Path::clean(FORMEA_THEME_PATH . '/' . $themeObject->name))) {
        Folder::delete(FORMEA_THEME_PATH . '/' . $themeObject->name);
      }

      if (is_dir(Path::clean(JPATH_ROOT . '/media/com_formea/css/theme/' . $themeObject->name))) {
        Folder::delete(JPATH_ROOT . '/media/com_formea/css/theme/' . $themeObject->name);
      }
      if (is_dir(Path::clean(JPATH_ROOT . '/media/com_formea/js/theme/' . $themeObject->name))) {
        Folder::delete(JPATH_ROOT . '/media/com_formea/js/theme/' . $themeObject->name);
      }
      if (is_dir(Path::clean(JPATH_ROOT . '/media/com_formea/img/theme/' . $themeObject->name))) {
        Folder::delete(JPATH_ROOT . '/media/com_formea/img/theme/' . $themeObject->name);
      }

      $retObject->setSuccess(true);
      $retObject->setResult((object) [
        'deleted_theme' => $themeObject
      ]);
    } catch (Exception $e) {
      $retObject->setSuccess(false);
      $retObject->setMsg($e->getMessage());
    }

    return $retObject;
  }
}
