<?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\Language\Text;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Model\ItemModel;
use Joomla\CMS\Table\Table;

/**
 * Model for gift card.
 *
 * @package     CMGiftCard
 * @subpackage  com_cmgiftcard
 * @since       1.0.0
 */
class CMGiftCardModelCard extends ItemModel
{
	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @param   string  $ordering   An optional ordering field.
	 * @param   string  $direction  An optional direction (asc|desc).
	 *
	 * @return  void
	 *
	 * @since   1.0.0
	 */
	protected function populateState($ordering = '', $direction = '')
	{
		$params = Factory::getApplication()->getParams();
		$this->setState('params', $params);

		parent::populateState($ordering, $direction);
	}

	/**
	 * 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();
	}

	/**
	 * Get a card.
	 *
	 * @param   integer  $pk  ID.
	 *
	 * @return  mixed
	 *
	 * @since   2.0.0-alpha1
	 */
	public function getItem($pk = null)
	{
		$code = Factory::getApplication()->input->get('code', '');

		return $this->getCardByCode($code);
	}

	/**
	 * Method to get create a new gift card.
	 *
	 * @param   array    $data     Gift card data.
	 * @param   integer  $orderId  The order ID which gift card belongs to.
	 *
	 * @return  mixed
	 *
	 * @since   1.0.0
	 */

	public function createCard($data, $orderId)
	{
		$data['order_id'] = $orderId;

		$table = Table::getInstance('Card', 'CMGiftCardTable');
		$params = ComponentHelper::getParams('com_cmgiftcard');
		$codeType = $params->get('card_code_type', 'random');
		$random = ($codeType == 'random') ? true : false;

		if (!$random)
		{
			$db = $this->getDbo();

			$subQuery = $db->getQuery(true)
				->select('COUNT(' . $db->qn('c.id') . ')')
				->from($db->qn('#__cmgiftcard_cards', 'c'))
				->where($db->qn('c.card_code') . ' = ' . $db->qn('a.code'));

			$query = $db->getQuery(true)
				->select($db->qn('a.code'))
				->from($db->qn('#__cmgiftcard_codes', 'a'))
				->where('(' . $subQuery->__toString() . ') = ' . $db->q(0))
				->where($db->qn('a.published') . ' = ' . $db->q(1))
				->order($db->qn('a.ordering') . ' ASC');
			$cardCode = $db->setQuery($query, 0, 1)->loadResult();

			$continue = (int) $params->get('out_of_predefined_code', 1);

			if ($cardCode == '' && $continue)
			{
				$random = true;
			}
			elseif ($cardCode == '' && !$continue)
			{
				Factory::getApplication()->enqueueMessage(Text::_('COM_CMGIFTCARD_ERROR_OUT_OF_PREDEFINED_CODE'), 'error');

				return false;
			}
		}

		if ($random)
		{
			$charType = $params->get('card_code_characters', 'alphanumeric');
			$length = (int) $params->get('card_code_length', 5);

			do
			{
				$cardCode = CMGiftCardHelper::generateRandomString($charType, $length);
				$cardCode = strtoupper($cardCode);
			} while($table->load(array('card_code' => $cardCode)));
		}

		$data['card_code'] = $cardCode;
		$table->reset();

		if (!$table->bind($data))
		{
			$this->setError($table->getError());

			return false;
		}

		if (!$table->check())
		{
			$this->setError($table->getError());

			return false;
		}

		if (!$table->store())
		{
			$this->setError($table->getError());

			return false;
		}

		return true;
	}

	/**
	 * 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;
	}
}
