<?php
/**
 * @package     CMGiftCard
 * @subpackage  com_cmgiftcard
 * @copyright   Copyright (C) 2016-2024 CMExension
 * @license     GNU General Public License version 2 or later
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Table\Table;
use Joomla\Utilities\ArrayHelper;

/**
 * Model class for gift card form.
 *
 * @package     CMGiftCard
 * @subpackage  com_cmgiftcard
 * @since       1.0.0
 */
class CMGiftCardModelCard extends AdminModel
{
	/**
	 * @var    string  The prefix to use with controller messages.
	 * @since  1.0.0
	 */
	protected $text_prefix = 'COM_CMGIFTCARD_CARD';

	/**
	 * Method to get a table object, load it if necessary.
	 *
	 * @param   string  $type    The table name. Optional.
	 * @param   string  $prefix  The class prefix. Optional.
	 * @param   array   $config  Configuration array for model. Optional.
	 *
	 * @return  Table   A Table object
	 *
	 * @since   1.0.0
	 */
	public function getTable($type = 'Card', $prefix = 'CMGiftCardTable', $config = array())
	{
		return Table::getInstance($type, $prefix, $config);
	}

	/**
	 * Abstract method for getting the form from the model.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
	 *
	 * @return  mixed  A Form object on success, false on failure
	 *
	 * @since   1.0.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		$form = $this->loadForm('com_cmgiftcard.card', 'card', array('control' => 'jform', 'load_data' => $loadData));

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

		return $form;
	}

	/**
	 * Method to get the data that should be injected in the form.
	 *
	 * @return  array  The default data is an empty array.
	 *
	 * @since   1.0.0
	 */
	protected function loadFormData()
	{
		$data = Factory::getApplication()->getUserState('com_cmgiftcard.edit.card.data', array());

		if (empty($data))
		{
			$data = $this->getItem();
		}

		return $data;
	}

	/**
	 * Prepare and sanitise the table data prior to saving.
	 *
	 * @param   Table  $table  A reference to a Table object.
	 *
	 * @return  void
	 *
	 * @since   1.0.0
	 */
	protected function prepareTable($table)
	{
		if (!empty($table->id))
		{
			$table->modified = Factory::getDate()->toSql();
			$table->modified_by = Factory::getUser()->get('id');
		}
	}

	/**
	 * Delete the gift cards which belong to specific orders.
	 *
	 * @param   array  $orderIds  Order IDs.
	 *
	 * @return  mixed
	 *
	 * @since   1.0.0
	 */
	public function deleteByOrder($orderIds)
	{
		ArrayHelper::toInteger($orderIds);

		if (count($orderIds))
		{
			$db = $this->getDbo();
			$query = $db->getQuery(true)
				->delete($db->qn('#__cmgiftcard_cards'))
				->where($db->qn('order_id') . ' IN (' . implode(',', $orderIds) . ')');
			$db->setQuery($query)->execute();
		}
	}

	/**
	 * Method to get a single record.
	 *
	 * @param   integer  $pk  The id of the primary key.
	 *
	 * @return  mixed    Object on success, false on failure.
	 *
	 * @since   1.0.0
	 */
	public function getItem($pk = null)
	{
		$pk = (!empty($pk)) ? $pk : (int) $this->getState($this->getName() . '.id');

		$db = $this->getDbo();

		$query = $db->getQuery(true)
			->select('a.*')
			->from($db->qn('#__cmgiftcard_cards') . ' AS a')
			->where($db->qn('a.id') . ' = ' . $db->q($pk));

		$query
			->select($db->qn('o.first_name') . ' AS sender_first_name')
			->select($db->qn('o.last_name') . ' AS sender_last_name')
			->select($db->qn('o.email') . ' AS sender_email')
			->select($db->qn('o.created') . ' AS created')
			->select($db->qn('o.completed') . ' AS completed')
			->select($db->qn('o.order_number') . ' AS order_number')
			->select($db->qn('o.order_status') . ' AS order_status')
			->join('LEFT', $db->qn('#__cmgiftcard_orders') . ' AS o ON '
				. $db->qn('o.id') . ' = ' . $db->qn('a.order_id')
			);

		$query->select($db->qn('d.image') . ' AS design_image')
			->select($db->qn('d.card_type') . ' AS card_type')
			->join('LEFT', $db->qn('#__cmgiftcard_designs') . ' AS d ON '
				. $db->qn('d.id') . ' = ' . $db->qn('a.design_id')
			);

		$amountSubQuery = $db->getQuery(true)
			->select('SUM(' . $db->qn('c.amount') . ')')
			->from($db->qn('#__cmgiftcard_cards') . ' AS c')
			->where($db->qn('c.order_id') . ' = ' . $db->qn('o.id'));

		$query->select('(' . $amountSubQuery . ') AS order_amount');

		return $db->setQuery($query)->loadObject();
	}

	/**
	 * Method to mark gift cards as delivered.
	 *
	 * @param   array   $ids   Gift card IDs.
	 * @param   string  $date  Delivery date.
	 *
	 * @return  boolean
	 *
	 * @since   1.2.0
	 */
	public function markDelivered($ids, $date)
	{
		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->update($db->qn('#__cmgiftcard_cards'))
			->set($db->qn('delivered') . ' = ' . $db->q($date))
			->where($db->qn('id') . ' IN (' . implode(',', $ids) . ')');

		return $db->setQuery($query)->execute();
	}

	/**
	 * Get gift card by its code.
	 *
	 * @param   string   $code   Gift card code.
	 *
	 * @return  mixed    Object on success, false on failure.
	 *
	 * @since   2.2.0
	 */
	public function getCardByCode($code)
	{
		$db = $this->getDbo();

		$query = $db->getQuery(true)
			->select('a.*')
			->from($db->qn('#__cmgiftcard_cards') . ' AS a')
			->where($db->qn('a.card_code') . ' = ' . $db->q($code));

		$query
			->select($db->qn('o.first_name') . ' AS sender_first_name')
			->select($db->qn('o.last_name') . ' AS sender_last_name')
			->select($db->qn('o.email') . ' AS sender_email')
			->select($db->qn('o.created') . ' AS created')
			->select($db->qn('o.completed') . ' AS completed')
			->select($db->qn('o.order_number') . ' AS order_number')
			->select($db->qn('o.order_status') . ' AS order_status')
			->join('LEFT', $db->qn('#__cmgiftcard_orders') . ' AS o ON '
				. $db->qn('o.id') . ' = ' . $db->qn('a.order_id')
			);

		$query->select($db->qn('d.image') . ' AS design_image')
			->select($db->qn('d.card_type') . ' AS card_type')
			->join('LEFT', $db->qn('#__cmgiftcard_designs') . ' AS d ON '
				. $db->qn('d.id') . ' = ' . $db->qn('a.design_id')
			);

		$amountSubQuery = $db->getQuery(true)
			->select('SUM(' . $db->qn('c.amount') . ')')
			->from($db->qn('#__cmgiftcard_cards') . ' AS c')
			->where($db->qn('c.order_id') . ' = ' . $db->qn('o.id'));

		$query->select('(' . $amountSubQuery . ') AS order_amount');

		return $db->setQuery($query)->loadObject();
	}

	/**
	 * Set coupon redemption status.
	 *
	 * @param   integer  $id        Gift card ID.
	 * @param   integer  $redeemed  1 for redeemed, 0 for not redeemed.
	 * @param   mixed    $date      Redeemed date.
	 *
	 * @return  bool
	 *
	 * @since   2.2.0
	 */
	public function setRedemptionStatus($id, $redeemed = -1, $date = null)
	{
		if (empty($id) || ($redeemed != 1 && $redeemed != 0)) return false;

		$db = $this->getDbo();

		if ($redeemed)
		{
			$date = $date ? $db->q($date) : $db->q(Factory::getDate()->toSql());
		}
		else
		{
			$date = 'NULL';
		}

		$query = $db->getQuery(true)
			->update($db->qn('#__cmgiftcard_cards'))
			->set($db->qn('redeemed') . ' = ' . $date)
			->where($db->qn('id') . ' = ' . $db->q($id));

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			$this->setError($e->getMessage());

			return false;
		}

		return true;
	}
}
