<?php
/**
 * @package         Conditions
 * @version         23.1.9739
 * 
 * @author          Peter van Westen <info@regularlabs.com>
 * @link            http://regularlabs.com
 * @copyright       Copyright © 2023 Regular Labs All Rights Reserved
 * @license         http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 */

namespace RegularLabs\Component\Conditions\Administrator\Helper;

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text as JText;
use RegularLabs\Library\ArrayHelper as RL_Array;
use RegularLabs\Library\Date as RL_Date;
use RegularLabs\Library\Language as RL_Language;

class Summary
{
    public static function render($condition, $extension = '', $message = '')
    {
        if ( ! $condition)
        {
            return '';
        }

        if ($extension && ! empty($condition->name))
        {
            RL_Language::load($extension);
        }

        $no_rules_set = '<div class="alert alert-warning">'
            . '<span class="icon-info-circle text-info" aria-hidden="true"></span> '
            . JText::_('CON_MESSAGE_NO_RULES_SELECTED')
            . ($message ? '<br><br>' . JText::_($message) : '')
            . '</div>';

        $html = [];

        if ($extension && ! empty($condition->name))
        {
            $html[] = '<h4>'
                . '<small class="text-uppercase text-muted">' . JText::_('CON_CONDITION_SET') . ':</small><br>'
                . $condition->name
                . '</h4>';
        }

        $output = self::getGroupsOutput($condition);

        if ($output === false)
        {
            $output = $no_rules_set;
        }

        $html[] = $output;

        return implode('', $html);
    }

    private static function getAttributeOutput($key, $value, $default = 'CON_NONE', $output_as_list = false)
    {
        if (is_array($value) && $output_as_list)
        {
            $value = '<ul><li>' . RL_Array::implode($value, '</li><li>') . '</li></ul>';
        }

        if (is_array($value))
        {
            $value = RL_Array::implode($value, ', ');
        }

        if (empty($value) && $value !== '0')
        {
            $value = JText::_('<em>%s</em>,' . $default);
        }

        return '<strong>' . $key . '</strong>: ' . $value;
    }

    private static function getAttributesOutputByRule($rule)
    {
        $attributes = [];

        foreach ($rule->params as $key => $value)
        {
            $output = self::getRuleLineOutput($rule, $key, $value);

            if ( ! $output)
            {
                continue;
            }

            $attributes[] = $output;
        }

        if (empty($attributes))
        {
            return '';
        }

        return '<div class="small">' . implode('<br>', $attributes) . '</div>';
    }

    private static function getDateTimeValue($value, $type, $recurring = false)
    {
        if ( ! $value)
        {
            return '<em>' . JText::_('CON_NOT_SPECIFIED') . '</em>';
        }

        if ($type == 'date__time')
        {
            return RL_Date::fixTime($value, false);
        }

        $format = $recurring
            ? 'd F H:i'
            : 'd F Y H:i';

        return Date::getString($value, $format, true);
    }

    private static function getGlue($match_all = true)
    {
        $text  = JText::_($match_all ? 'CON_AND' : 'CON_OR');
        $class = $match_all ? 'bg-info' : 'bg-warning text-black';

        return '<div class="text-center"><span class="badge px-4 ' . $class . '">' . $text . '</span></div>';
    }

    private static function getGroupsOutput($condition)
    {
        $condition->groups = RL_Array::clean($condition->groups ?? []);

        if (empty($condition->groups))
        {
            return false;
        }

        $groups = [];

        foreach ($condition->groups as $group)
        {
            $groups[] = self::getOutputByGroup($group);
        }

        $groups = RL_Array::clean($groups);

        if (empty($groups))
        {
            return false;
        }

        if (count($groups) < 2)
        {
            $html[] = implode('', $groups);

            return implode('', $html);
        }

        foreach ($groups as &$group)
        {
            $group = '<div class="card border-dark rl-card"><div class="card-body">' . $group . '</div></div>';
        }

        $html[] = implode(self::getGlue($condition->match_all), $groups);

        return implode('', $html);
    }

    private static function getNameString($name, $type = '')
    {
        $id = str_replace('-', '_', $name);

        $field = Helper::getField($type . '.' . $id) ?? Helper::getField($id) ?? null;

        if ( ! $field || ! isset($field->name))
        {
            return JText::_($name);
        }

        $name = trim($field->name);

        if (empty($field->attributes['group_name']))
        {
            return JText::_($name);
        }

        return JText::_($field->attributes['group_name']) . ': ' . JText::_($name);
    }

    private static function getOutputByGroup($group)
    {
        $rules = [];

        foreach ($group->rules as $rule)
        {
            $rules[] = self::getOutputByRule($rule);
        }

        return implode(self::getGlue($group->match_all), $rules);
    }

    private static function getOutputByRule($rule)
    {
        $html = [];

        $state       = self::getNameString('exclude.' . $rule->exclude);
        $state_class = $rule->exclude ? 'danger' : 'success';
        $type_name   = self::getNameString('type.' . $rule->type);

        $values_output     = self::getValuesOutputByRule($rule);
        $attributes_output = self::getAttributesOutputByRule($rule);

        $class = 'alert alert-' . $state_class;

        if (isset($rule->disabled) && $rule->disabled)
        {
            $class .= ' disabled ghosted';
        }

        $html[] = '<div class="' . $class . '">';

        if (isset($rule->disabled) && $rule->disabled)
        {
            $html[] = '<div class="alert alert-danger">'
                . JText::_('RL_ONLY_AVAILABLE_IN_PRO')
                . '</div>';
        }

        $html[] = '<h3>'
            . '<span class="badge bg-' . $state_class . ' align-text-bottom">' . $state . '</span> '
            . $type_name
            . '</h3>';

        $html[] = $values_output;
        $html[] = $attributes_output;

        $html[] = '</div>';

        return implode('', $html);
    }

    private static function getRuleLineOutput($rule, $key, $value)
    {
        switch ($rule->type)
        {
            case 'date__date':
            case 'date__time':
            case 'content__article__date':
            case 'content__article__field':
                return '';

            default:
                return self::getRuleLineOutputDefault($rule, $key, $value);
        }
    }

    private static function getRuleLineOutputDefault($rule, $key, $value)
    {
        if ($key === 'selection')
        {
            return '';
        }

        $key = $rule->type . '__' . $key;

        $name = self::getNameString($key);

        if ($name === $key)
        {
            return '';
        }

        $value = self::getValues($value, $key);

        return self::getAttributeOutput($name, $value);
    }

    private static function getValues($values, $key)
    {
        if (empty($values) && $values !== '0')
        {
            return [];
        }

        $field = Helper::getField($key);

        if ( ! $field)
        {
            return $values;
        }
        if ($field->type == 'Radio')
        {
            return self::getNameString($key . '.' . $values);
        }

        if ( ! is_array($values))
        {
            $values = [$values];
        }

        $class = Helper::getFieldClass($key);

        if ($class)
        {
            $values = $class->getNamesByIds($values, $field->attributes);
        }
        else
        {
            foreach ($values as &$value)
            {
                $value = self::getNameString($value, $key);
            }
        }

        if (count($values) < 6)
        {
            return $values;
        }

        $values   = array_slice($values, 0, 5);
        $values[] = '...';

        return $values;
    }

    private static function getValuesOutputByRule($rule)
    {
        switch ($rule->type)
        {
            case 'date__date':
            case 'date__time':
            case 'content__article__date':
                return self::getValuesOutputByRuleDateTime($rule);

            case 'content__article__field':
                return self::getValuesOutputByRuleField($rule);

            default:
                return self::getValuesOutputByRuleDefault($rule);
        }
    }

    private static function getValuesOutputByRuleDateTime($rule)
    {
        $name = isset($rule->params->selection)
            ? self::getNameString($rule->params->selection, $rule->type)
            : '';

        if ($rule->params->comparison == 'between')
        {
            return self::getValuesOutputByRuleDateTimeBetween($rule, $name);
        }

        return self::getValuesOutputByRuleDateTimeBeforeOrAfter($rule, $name);
    }

    private static function getValuesOutputByRuleDateTimeBeforeOrAfter($rule, $name)
    {
        $value = $rule->params->date ?? $rule->params->time;

        $type   = $rule->params->type ?? 'specific';

        $value = $type == 'now'
            ? JText::_('CON_NOW')
            : self::getDateTimeValue($value, $rule->type, false);

        $comparison = JText::_('CON_DATE_' . $rule->params->comparison);

        if ($name)
        {
            $comparison = self::lowerCaseFirst($comparison);
        }

        return '<strong>' . $name . '</strong>'
            . ' ' . $comparison
            . ' <code>' . $value . '</code>';
    }

    private static function getValuesOutputByRuleDateTimeBetween($rule, $name)
    {
        $recurring = ($rule->params->recurring ?? false);

        $value_from = self::getDateTimeValue($rule->params->from, $rule->type, $recurring);
        $value_to   = self::getDateTimeValue($rule->params->to, $rule->type, $recurring);

        $string = $recurring ? 'CON_BETWEEN_A_AND_B_EVERY_YEAR' : 'CON_BETWEEN_A_AND_B';

        $value = JText::sprintf(
            $string,
            '<code class="text-nowrap">' . $value_from . '</code>',
            '<code class="text-nowrap">' . $value_to . '</code>'
        );

        if ($name)
        {
            $value = self::lowerCaseFirst($value);
        }

        return '<strong>' . $name . '</strong>'
            . ' ' . $value;
    }

    private static function getValuesOutputByRuleDefault($rule)
    {
        $values = null;

        foreach ($rule->params as $key => $value)
        {
            if ($key !== 'selection')
            {
                continue;
            }

            $values = self::getValues($value, $rule->type);
        }

        if (is_null($values))
        {
            return '';
        }

        if (RL_Array::implode($values, '') === '')
        {
            return '<ul><li>' . JText::_('<em>%s</em>,CON_NONE') . '</li></ul>';
        }

        $state_class = $rule->exclude ? 'danger' : 'success';

        $fields = Helper::getField($rule->type);

        if ($fields && in_array($fields->type, ['Editor', 'Textarea']))
        {
            return '<pre class="p-2 my-1 border border-' . $state_class . ' rounded"><code>'
                . htmlentities(RL_Array::implode($values, '<br>'))
                . '</code></pre>';
        }

        return '<ul><li>' . RL_Array::implode($values, '</li><li>') . '</li></ul>';
    }

    private static function getValuesOutputByRuleField($rule)
    {
        $id   = $rule->type . '__field';
        $name = $rule->params->field;

        $field = Helper::getField($id);
        $class = Helper::getFieldClass($id);

        if ($field && $class && method_exists($class, 'getNameById'))
        {
            $name = $class->getNameById($rule->params->field, $field->attributes);
        }

        $comparison = JText::_('CON_COMPARISON_' . strtoupper($rule->params->comparison));

        return '<strong>' . $name . '</strong>'
            . ' <code>' . self::lowerCaseFirst($comparison) . '</code> '
            . $rule->params->value;
    }

    private static function lowerCaseFirst($string)
    {
        return strtolower($string[0]) . substr($string, 1);
    }
}
