<?php

use EventEspresso\core\domain\services\messages\MessageTemplateValidator;
use EventEspresso\core\services\loaders\LoaderFactory;
use EventEspresso\core\services\request\RequestInterface;

/**
 * EEM_Message_Template_Group
 *
 * @package     Event Espresso
 * @subpackage  includes/models/EEM_Message_Template_Group.model.php
 * @author      Darren Ethier
 */
class EEM_Message_Template_Group extends EEM_Soft_Delete_Base
{
    protected static ?EEM_Message_Template_Group $_instance = null;


    /**
     * @param string|null $timezone
     * @throws EE_Error
     */
    protected function __construct(?string $timezone = '')
    {
        $this->singular_item    = esc_html__('Message Template Group', 'event_espresso');
        $this->plural_item      = esc_html__('Message Template Groups', 'event_espresso');
        $this->_tables          = [
            'Message_Template_Group' => new EE_Primary_Table('esp_message_template_group', 'GRP_ID'),
        ];
        $this->_fields          = [
            'Message_Template_Group' => [
                'GRP_ID'           => new EE_Primary_Key_Int_Field(
                    'GRP_ID',
                    esc_html__('Message Template Group ID', 'event_espresso')
                ),
                'MTP_name'         => new EE_Plain_Text_Field(
                    'MTP_name',
                    esc_html__('The name of the template group', 'event_espresso'),
                    false,
                    ''
                ),
                'MTP_description'  => new EE_Simple_HTML_Field(
                    'MTP_description',
                    esc_html__(
                        'A brief description about this template.',
                        'event_espresso'
                    ),
                    false,
                    ''
                ),
                'MTP_user_id'      => new EE_WP_User_Field(
                    'MTP_user_id',
                    esc_html__('Template Creator ID', 'event_espresso'),
                    false
                ),
                'MTP_messenger'    => new EE_Plain_Text_Field(
                    'MTP_messenger',
                    esc_html__(
                        'Messenger Used for Template',
                        'event_espresso'
                    ),
                    false,
                    'email'
                ),
                'MTP_message_type' => new EE_Plain_Text_Field(
                    'MTP_message_type',
                    esc_html__('Message Type', 'event_espresso'),
                    false,
                    'registration'
                ),
                'MTP_is_global'    => new EE_Boolean_Field(
                    'MTP_is_global',
                    esc_html__(
                        'Flag indicating if Template Group is Global',
                        'event_espresso'
                    ),
                    false,
                    true
                ),
                'MTP_is_override'  => new EE_Boolean_Field(
                    'MTP_is_override',
                    esc_html__(
                        'Flag indicating if Template Group overrides any other Templates for the messenger/messagetype combination',
                        'event_espresso'
                    ),
                    false,
                    false
                ),
                'MTP_deleted'      => new EE_Trashed_Flag_Field(
                    'MTP_deleted',
                    esc_html__(
                        'Flag indicating whether this has been trashed',
                        'event_espresso'
                    ),
                    false,
                    false
                ),
                'MTP_is_active'    => new EE_Boolean_Field(
                    'MTP_is_active',
                    esc_html__(
                        'Flag indicating whether template group is active',
                        'event_espresso'
                    ),
                    false,
                    true
                ),
            ],
        ];
        $this->_model_relations = [
            'Message_Template' => new EE_Has_Many_Relation(),
            'Message'          => new EE_Has_Many_Relation(),
            'Event'            => new EE_HABTM_Relation('Event_Message_Template'),
            'WP_User'          => new EE_Belongs_To_Relation(),
        ];
        foreach ($this->_cap_contexts_to_cap_action_map as $context => $action) {
            $this->_cap_restriction_generators[ $context ] = new EE_Restriction_Generator_Global('MTP_is_global');
        }
        $this->_caps_slug = 'messages';

        parent::__construct($timezone);
    }


    /**
     * get_all_trashed_message_templates_by_event
     *
     * @access public
     * @param int    $EVT_ID specific event id
     * @param string $orderby
     * @param string $order
     * @param null   $limit
     * @param bool   $count
     * @return array message template objects that are attached to a specific event.
     */
    public function get_all_trashed_message_templates_by_event(
        $EVT_ID,
        $orderby = 'GRP_ID',
        $order = 'ASC',
        $limit = null,
        $count = false
    ) {
        $query_params = [['Event.EVT_ID' => $EVT_ID], 'order_by' => [$orderby => $order], 'limit' => $limit];
        return $count ? $this->count_deleted($query_params, 'GRP_ID', true) : $this->get_all_deleted($query_params);
    }


    /**
     * get_all_message_templates_by_messenger
     *
     * @access public
     * @param        $messenger
     * @param string $orderby
     * @param string $order
     * @return array all (including trashed or inactive) message template group objects for the given messenger
     */
    public function get_all_message_templates_by_messenger($messenger, $orderby = 'GRP_ID', $order = 'ASC')
    {
        return $this->get_all_deleted_and_undeleted(
            [['MTP_messenger' => $messenger], 'order_by' => [$orderby => $order]]
        );
    }


    /**
     * This simply adds on any messenger/message type filters that may be present in the request
     *
     * @param array $_where any existing where conditions to append these to.
     * @return array          original where conditions or original with additional filters.
     */
    protected function _maybe_mtp_filters($_where = [])
    {
        /** @var RequestInterface $request */
        $request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
        $messenger = $request->getRequestParam('ee_messenger_filter_by');
        // account for messenger or message type filters
        if ($messenger !== '' && $messenger !== 'none_selected' && $messenger !== 'all') {
            $_where['MTP_messenger'] = $messenger;
        }
        $message_type = $request->getRequestParam('ee_message_type_filter_by');
        if (
            $message_type !== '' && $message_type !== 'none_selected'
        ) {
            $_where['MTP_message_type'] = $message_type;
        }

        return $_where;
    }


    /**
     * get_all_active_message_templates groups
     *
     * @access public
     * @param string $orderby
     * @param string $order
     * @param null   $limit
     * @param bool   $count
     * @param bool   $global
     * @param bool   $user_check
     * @return array|int all active (non_trashed, active) message template objects
     */
    public function get_all_active_message_templates(
        $orderby = 'GRP_ID',
        $order = 'ASC',
        $limit = null,
        $count = false,
        $global = true,
        $user_check = false
    ) {
        $_where                  = $global ? ['MTP_is_global' => true] : ['MTP_is_global' => false];
        $_where['MTP_is_active'] = true;
        $_where                  = $this->_maybe_mtp_filters($_where);

        if (
            $user_check
            && ! $global
            && ! EE_Registry::instance()->CAP->current_user_can(
                'ee_read_others_messages',
                'get_all_active_message_templates'
            )
        ) {
            $_where['MTP_user_id'] = get_current_user_id();
        }

        $query_params = [$_where, 'order_by' => [$orderby => $order], 'limit' => $limit];

        return $count ? $this->count($query_params, 'GRP_ID', true) : $this->get_all($query_params);
    }


    /**
     *    retrieve ALL message_template groups from db regardless of wht
     *
     * @access    public
     * @param string $orderby
     * @param string $order
     * @param null   $limit
     * @param bool   $count
     * @return mixed array on success, FALSE on fail
     */
    public function get_all_message_templates($orderby = 'GRP_ID', $order = 'ASC', $limit = null, $count = false)
    {
        $_where = $this->_maybe_mtp_filters();

        $query_params = [$_where, 'order_by' => [$orderby => $order], 'limit' => $limit];

        $r_templates = $count
            ? $this->count_deleted_and_undeleted($query_params, 'GRP_ID', true)
            : $this->get_all_deleted_and_undeleted($query_params);

        return $r_templates;
    }


    /**
     * This gets all the custom templates attached to a specific event
     *
     * @param int   $EVT_ID       event id
     * @param array $query_params @see
     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
     * @return  EE_Message_Template_Group[]
     */
    public function get_all_custom_templates_by_event($EVT_ID, $query_params = [])
    {
        $where = array_merge($query_params, ['Event.EVT_ID' => $EVT_ID]);
        return $this->get_all(
            [$where]
        );
    }


    /**
     * get_all_trashed_grouped_message_templates
     * this returns ONLY the template groups where ALL contexts are trashed and none of the group are non-trashed
     *
     * @access public
     * @param string $orderby
     * @param string $order
     * @param null   $limit
     * @param bool   $count
     * @param bool   $global
     * @return array|int EE_Message_Template_Group[] message template groups.
     */
    public function get_all_trashed_grouped_message_templates(
        $orderby = 'GRP_ID',
        $order = 'ASC',
        $limit = null,
        $count = false,
        $global = true
    ) {
        $_where                  = $global ? ['MTP_is_global' => true] : ['MTP_is_global' => false];
        $_where['MTP_is_active'] = true;
        $_where                  = $this->_maybe_mtp_filters($_where);

        $query_params = [$_where, 'order_by' => [$orderby => $order], 'limit' => $limit];

        return $count ? $this->count_deleted($query_params, 'GRP_ID', true) : $this->get_all_deleted($query_params);
    }


    /**
     * this returns the message template group(s) for a given event, messenger, and message template
     *
     * @param string              $messenger
     * @param string              $message_type
     * @param                     $evt_id
     * @param string              $orderby pointless at this point but still included
     * @param string              $order
     * @param mixed (array|null) $limit   array($offset, $num)
     * @param bool                $count   true = just return count, false = objects
     * @param bool                $active  ignore "active" or not. (default only return active)
     * @return \mixed[]) depending on $count.
     */
    public function get_event_message_templates_by_m_and_mt_and_evt(
        $messenger,
        $message_type,
        $evt_id,
        $orderby = 'GRP_ID',
        $order = 'ASC',
        $limit = null,
        $count = false,
        $active = true
    ) {
        $_where = [
            'MTP_messenger'    => $messenger,
            'MTP_message_type' => $message_type,
            'Event.EVT_ID'     => $evt_id,
            'MTP_is_global'    => true,
            'MTP_is_active'    => $active,
        ];

        $query_params = [$_where, 'order_by' => [$orderby => $order], 'limit' => $limit];

        return $count ? $this->count($query_params, 'GRP_ID', true) : $this->get_all($query_params);
    }


    /**
     * get all GLOBAL message template groups for the given messenger and message type
     *
     * @param string $messenger     slug for messenger
     * @param string $message_type  slug for message type
     * @param string $orderby       what column to orderby
     * @param string $order         ASC or DESC
     * @param mixed (array|null) $limit array($offset, $num)
     * @param bool   $count         true = just return count, false = objects
     * @param bool   $active        ignore "active" or not. (default only return active) -
     *                              'all' means return both inactive AND inactive.
     * @return array               message template objects that are global (i.e. non-event)
     */
    public function get_global_message_template_by_m_and_mt(
        $messenger,
        $message_type,
        $orderby = 'GRP_ID',
        $order = 'ASC',
        $limit = null,
        $count = false,
        $active = true
    ) {
        $_where = [
            'MTP_messenger'    => $messenger,
            'MTP_message_type' => $message_type,
            'MTP_is_global'    => true,
        ];

        if ($active != 'all') {
            $_where['MTP_is_active'] = $active;
        }

        $query_params = [$_where, 'order_by' => [$orderby => $order], 'limit' => $limit];

        return $count ? $this->count($query_params, 'GRP_ID', true) : $this->get_all($query_params);
    }


    /**
     * get all custom message template groups for the given messenger and message type
     *
     * @param string $messenger    messenger
     * @param string $message_type messagetype
     * @param array  $query_params same as EEM_Base->get_all()
     * @return EE_Message_Template_Group[]
     */
    public function get_custom_message_template_by_m_and_mt($messenger, $message_type, $query_params = [])
    {
        return $this->get_all(
            array_merge(
                $query_params,
                [
                    [
                        'MTP_is_global'    => false,
                        'MTP_messenger'    => $messenger,
                        'MTP_message_type' => $message_type,
                    ],
                ]
            )
        );
    }


    /**
     * This sends things to the validator for the given messenger and message type.
     *
     * @param array  $fields       the incoming fields to check.
     *                             Note this array is in the formatted fields from the form fields setup.
     *                             So we need to reformat this into an array of expected field refs by the validator.
     *                             Note also that this is not only the fields for the Message Template Group
     *                             but ALSO for Message Template.
     * @param string $context      The context the fields were obtained from.
     * @param string $messenger    The messenger we are validating
     * @param string $message_type The message type we are validating.
     * @return bool
     * @throws DomainException
     */
    public function validate(array $fields, string $context, string $messenger, string $message_type): bool
    {
        /** @var MessageTemplateValidator $validator */
        $validator = LoaderFactory::getShared(MessageTemplateValidator::class);
        return $validator->validateTemplateFields($messenger, $message_type, $context, $fields);
    }


    /**
     * Updates all message template groups matching the incoming arguments to inactive status.
     *
     * @param array $messenger_names    The messenger slugs.
     *                                  If empty then all templates matching the message types are marked inactive.
     *                                  Otherwise only templates matching the messengers and message types.
     * @param array $message_type_names The message type slugs.
     *                                  If empty then all templates matching the messengers are marked inactive.
     *                                  Otherwise only templates matching the messengers and message types.
     * @return int  count of updated records.
     */
    public function deactivate_message_template_groups_for($messenger_names = [], $message_type_names = [])
    {
        $query_args = [];
        if (empty($messenger_names) && empty($message_type_names)) {
            return 0;
        }
        if (! empty($messenger_names)) {
            $query_args[0]['MTP_messenger'] = ['IN', (array) $messenger_names];
        }
        if (! empty($message_type_names)) {
            $query_args[0]['MTP_message_type'] = ['IN', (array) $message_type_names];
        }
        return $this->update(['MTP_is_active' => false], $query_args);
    }
}
