<?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\FsrDate;
use Feseur\Library\FsrResponse;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Mail\Mail;
use Joomla\CMS\Mail\MailerFactoryInterface;
use Joomla\Component\Formea\Site\Helper\FormeaGeneralHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Filesystem\Path;
use stdClass;

class FormeaSubmission
{
  /** The submission id
   * @var int
   * @since 1.0.0
   */
  public $id;

  /**
   * @var DatabaseDriver
   * @since 1.0.0
   */
  protected $db;

  /**
   * @var stdClass | null
   * @since 1.0.0
   */
  public $submissionObject = null;

  /**
   * @var array | null
   * @since 1.0.0
   */
  public $submissionData = null;

  /**
   * @var CMSApplicationInterface|null
   * @since 1.0.3
   */
  protected $app;

  /**
   * @var mixed|string
   * @since 1.0.3
   */
  public $langTag;

  /**
   * @param   int  $id  Submission ID
   *
   * @since 1.0.0
   */
  public function __construct($id, $config = [])
  {
    $this->id  = $id;
    $container = Factory::getContainer();
    $this->app = Factory::getApplication();
    $this->db  = $container->get('DatabaseDriver');
    if (isset($config['langTag'])) {
      $this->langTag = $config['langTag'];
    } else {
      $this->langTag = $this->app->getLanguage()->getTag();
    }
  }

  public function getSubmissionObject()
  {
    if (is_null($this->submissionObject)) {
      $db    = $this->db;
      $query = $db->getQuery(true);
      $query->select('*');
      $query->from($db->quoteName('#__formea_submissions'));
      $query->where($db->quoteName('id') . ' = ' . $db->quote($this->id));
      $db->setQuery($query);
      $submission             = $db->loadObject();
      $this->submissionObject = $submission;
    }

    return $this->submissionObject;
  }

  public function getSubmissionData()
  {
    if (is_null($this->submissionData)) {
      //
      $db    = $this->db;
      $query = $db->getQuery(true);
      $query->select('*');
      $query->from($db->quoteName('#__formea_submission_data'));
      $query->where($db->quoteName('submission_id') . ' = ' . $db->quote($this->id));
      $db->setQuery($query);
      $submission           = $db->loadObjectList();
      $this->submissionData = $submission;
    }

    return $this->submissionData;
  }

  /**
   *
   *
   * @since 1.2.0
   */
  public function processPlaceHolders($submission_url = "")
  {

    $placeholders = FormeaGeneralHelper::getGlobalPlaceholders($submission_url);

    //get submitted data
    $submitted_data = $this->getSubmissionData();

    $totalSubmittedData = count($submitted_data);
    $groupIds           = [];
    for ($i = 0; $i < $totalSubmittedData; $i++) {
      $gp = "";
      if ($submitted_data[$i]->group_id > 0) {
        $groupIds[$submitted_data[$i]->group_id] = $submitted_data[$i]->group_id;
        //group
        $gp = "GP_" . $submitted_data[$i]->group_id . '_';
        if ($submitted_data[$i]->setIndex > 0) {
          $gp = "GP_" . $submitted_data[$i]->group_id . '_' . $submitted_data[$i]->setIndex . '_';
        }
      }


      $alias_name       = $submitted_data[$i]->field_name;
      $k                = $gp . $alias_name . ':VALUE';
      $placeholders[$k] = $submitted_data[$i]->field_value;
      $k                = $gp . $alias_name . ':CAPTION';
      $placeholders[$k] = $submitted_data[$i]->field_caption;
      if ((int) $submitted_data[$i]->is_link > 0) {
        $k         = $gp . $alias_name . ':LINK';
        $kp        = $gp . $alias_name . ':PATH';
        $fileLinks = [];
        $filePaths = [];
        if (!empty($submitted_data[$i]->link_path)) {
          $storedLinks = json_decode($submitted_data[$i]->link_path);
          $filePaths   = json_decode($submitted_data[$i]->dir_path);
          $totalLinks  = count($storedLinks);
          for ($m = 0; $m < $totalLinks; $m++) {
            $pathInfoFileName = pathinfo($storedLinks[$m], PATHINFO_FILENAME);
            $extension        = pathinfo($storedLinks[$m], PATHINFO_EXTENSION);

            $fileLinks[] = '<a href="' . $storedLinks[$m] . '" target="_blank" download>' . $pathInfoFileName . '.' . $extension . '</a>';
          }
        }
        $placeholders[$k]  = implode('<br/>', $fileLinks);
        $placeholders[$kp] = implode('<br/>', $filePaths);
      }
    }
    if (!empty($groupIds)) {
      $groupIds     = array_values($groupIds);
      $placeholders = $this->getGroupsPlaceholders($submitted_data, $groupIds, $placeholders);
    }

    return $placeholders;
  }

  public function getFormEmailParam()
  {
    $submissionObject = $this->getSubmissionObject();
    $form_id          = $submissionObject->form_id;
    $gotEmails        = false;
    $confirmedEmail   = [];
    $db               = $this->db;
    $query            = $db->getQuery(true);
    $query->select('*');
    $query->from($db->quoteName('#__formea_formemails'));
    $query->where($db->quoteName('form_id') . ' = ' . $db->quote($form_id));
    $db->setQuery($query);
    $emails      = $db->loadObjectList();
    $totalEmails = count($emails);
    for ($i = 0; $i < $totalEmails; $i++) {
      $emailcontents = [];
      if (!empty($emails[$i]->from_email) && !empty($emails[$i]->to_email)) {
        $gotEmails = true;
        $query->clear();
        $query->select('*');
        $query->from($db->quoteName('#__formea_formemailcontent'));
        $query->where($db->quoteName('form_id') . ' = ' . $db->quote($form_id));
        $query->where($db->quoteName('email_id') . ' = ' . $db->quote($emails[$i]->id));
        $db->setQuery($query);
        $emailcontents = $db->loadAssocList('language');
        $email_content = FormeaGeneralHelper::getDefaultLangValField([
          'id',
          'form_id',
          'email_id',
          'from_name',
          'replyto_name',
          'subject',
          'attachments',
          'email_content',
          'language',
        ], $emailcontents, $this->langTag);
        if (!empty($email_content)) {
          $email_content = (object) $email_content;
        }

        if (isset($email_content->attachments)) {
          if (!empty($email_content->attachments)) {
            $email_content->attachments = json_decode($email_content->attachments);
          }
        } else {
          $email_content->attachments = [];
        }

        $emails[$i]->email_content  = $email_content;
        $emails[$i]->email_contents = $emailcontents;
        $confirmedEmail[]           = $emails[$i];
      }
    }

    return $confirmedEmail;
  }

  /**
   * @param $data
   *
   * @return FsrResponse
   *
   * @since 1.0.4
   */
  public function sendMail($data = [])
  {
    $retObject = new FsrResponse();
    try {
      $submissionObject = $this->getSubmissionObject();
      $submission_url   = $submissionObject->submitted_url;
      if (empty($submission_url)) {
        $submission_url = '';
      }
      //getEmailParam
      $confirmedEmail = $this->getFormEmailParam();


      if (empty($confirmedEmail)) {
        throw new Exception('Invalid email parameters');
      }

      //set placeholders
      if (!empty($confirmedEmail)) {
        $placeholders = $this->processPlaceHolders($submission_url);
        //get submitted data
        $submitted_data     = $this->getSubmissionData();
        $totalSubmittedData = count($submitted_data);
        for ($i = 0; $i < $totalSubmittedData; $i++) {
          //  $alias_name       = strtoupper(str_replace('-', '_', $submitted_data[$i]->field_name));
          $alias_name       = $submitted_data[$i]->field_name;
          $k                = $alias_name . ':VALUE';
          $placeholders[$k] = $submitted_data[$i]->field_value;
          $k                = $alias_name . ':CAPTION';
          $placeholders[$k] = $submitted_data[$i]->field_caption;
          if ((int) $submitted_data[$i]->is_link > 0) {
            $k         = $alias_name . ':LINK';
            $kp        = $alias_name . ':PATH';
            $fileLinks = [];
            $filePaths = [];
            if (!empty($submitted_data[$i]->link_path)) {
              $storedLinks = json_decode($submitted_data[$i]->link_path);
              $filePaths   = json_decode($submitted_data[$i]->dir_path);
              $totalLinks  = count($storedLinks);
              for ($m = 0; $m < $totalLinks; $m++) {
                $pathInfoFileName = pathinfo($storedLinks[$m], PATHINFO_FILENAME);
                $extension        = pathinfo($storedLinks[$m], PATHINFO_EXTENSION);

                $fileLinks[] = '<a href="' . $storedLinks[$m] . '" target="_blank" download>' . $pathInfoFileName . '.' . $extension . '</a>';
              }
            }
            $placeholders[$k]  = implode('<br/>', $fileLinks);
            $placeholders[$kp] = implode('<br/>', $filePaths);
          }
        }

        $totalConfirmed = count($confirmedEmail);
        //  $mailer         = Factory::getMailer();
        /** @var Mail $mailer */
        $mailer                = Factory::getContainer()->get(MailerFactoryInterface::class)->createMailer();
        $date                  = new FsrDate();
        $user                  = $this->app->getIdentity();
        $adminErrors           = [];
        $userErrors            = [];
        $toBeUpdated           = [
          'id'               => $this->id,
          'user_email'       => '',
          'user_email_sent'  => 0,
          'admin_email'      => '',
          'admin_email_sent' => 0,
          'modified_date'    => $date->toSql(),
          'modified_by'      => (!empty($user->id)) ? $user->id : 0,
        ];
        $formeaAttachmentClass = new FormeaAttachment();
        $adminEmails           = [];
        $userEmails            = [];

        for ($i = 0; $i < $totalConfirmed; $i++) {
          foreach ($placeholders as $key => $value) {
            $key                                              = strtoupper($key);
            $confirmedEmail[$i]->from_email                   = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->from_email ?? '');
            $confirmedEmail[$i]->to_email                     = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->to_email ?? '');
            $confirmedEmail[$i]->replyto_email                = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->replyto_email ?? '');
            $confirmedEmail[$i]->cc_email                     = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->cc_email ?? '');
            $confirmedEmail[$i]->bcc_email                    = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->bcc_email ?? '');
            $confirmedEmail[$i]->email_content->from_name     = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->email_content->from_name ?? '');
            $confirmedEmail[$i]->email_content->replyto_name  = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->email_content->replyto_name ?? '');
            $confirmedEmail[$i]->email_content->subject       = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->email_content->subject ?? '');
            $confirmedEmail[$i]->email_content->email_content = str_replace('[' . $key . ']', $value, $confirmedEmail[$i]->email_content->email_content ?? '');
            $attachments                                      = [];
            foreach ($confirmedEmail[$i]->email_content->attachments as $attachment) {
              $attachments[] = str_replace('[' . $key . ']', $value, $attachment ?? '');
            }
            $confirmedEmail[$i]->email_content->attachments = $attachments;
          }

          $passed          = true;
          $sent            = false;
          $checkerKey      = [
            'from_email',
            'to_email',
          ];
          $totalCheckerKey = count($checkerKey);
          for ($j = 0; $j < $totalCheckerKey; $j++) {
            $splitEmailAddress   = explode(',', $confirmedEmail[$i]->{$checkerKey[$j]});
            $totalEmailAddresses = count($splitEmailAddress);
            for ($l = 0; $l < $totalEmailAddresses; $l++) {
              if (!filter_var($splitEmailAddress[$l], FILTER_VALIDATE_EMAIL)) {
                if ((int) $confirmedEmail[$i]->target_type == 0) {
                  $adminErrors[] = $splitEmailAddress[$l] . ' is an invalid email.';
                } else {
                  $userErrors[] = $splitEmailAddress[$l] . ' is an invalid email.';
                }
                $logText = $splitEmailAddress[$l] . ' is invalid email. | submission_id: ' . $this->id;
                Log::add($logText, Log::ERROR, 'com_formea');
                $passed = false;
                break;
              }
            }
          }
          if ($passed) {
            if ((int) $confirmedEmail[$i]->target_type == 0) {
              $toBeUpdated['admin_email'] = $confirmedEmail[$i]->to_email;
              $adminEmails[]              = $confirmedEmail[$i]->to_email;
            } else {
              $toBeUpdated['user_email'] = $confirmedEmail[$i]->to_email;
              $userEmails[]              = $confirmedEmail[$i]->to_email;
            }
            $mailer->setSender([$confirmedEmail[$i]->from_email, $confirmedEmail[$i]->email_content->from_name]);
            $mailer->clearAllRecipients();
            $mailer->clearAttachments();
            $mailer->clearReplyTos();
            $mailer->setSubject($confirmedEmail[$i]->email_content->subject);
            $mailer->setBody($confirmedEmail[$i]->email_content->email_content);
            $mailer->isHtml(true);
            $mailer->addRecipient(explode(',', $confirmedEmail[$i]->to_email));
            if (!empty($confirmedEmail[$i]->replyto_email)) {
              $mailer->addReplyTo($confirmedEmail[$i]->replyto_email, $confirmedEmail[$i]->email_content->replyto_name);
            }
            if (!empty($confirmedEmail[$i]->cc_email)) {
              $mailer->addCc(explode(',', $confirmedEmail[$i]->cc_email));
            }
            if (!empty($confirmedEmail[$i]->bcc_email)) {
              $mailer->addBcc(explode(',', $confirmedEmail[$i]->bcc_email));
            }
            if (!empty($confirmedEmail[$i]->email_content->attachments)) {
              $processedFiles = $formeaAttachmentClass->getRelativeFiles($confirmedEmail[$i]->email_content->attachments);
              $totalFiles     = count($processedFiles);
              for ($n = 0; $n < $totalFiles; $n++) {
                if ($processedFiles[$n]->adapter !== 'placeholder' && !empty($processedFiles[$n]->cleaned_path)) {
                  $mailer->addAttachment($processedFiles[$n]->cleaned_path);
                }
              }
            }

            $sendResult = $mailer->Send();
            if ($sendResult !== true) {
              if ((int) $confirmedEmail[$i]->target_type == 0) {
                $adminErrors[] = $sendResult->getMessage();
              } else {
                $userErrors[] = $sendResult->getMessage();
              }
              $logText = $sendResult->getMessage() . ' | submission_id: ' . $this->id;
              Log::add($logText, Log::ERROR, 'com_formea');
              $confirmedEmail[$i]->send_result = (object) array(
                'success' => false,
                'msg'     => $sendResult->getMessage()
              );
              $sent                            = false;
            } else {
              $confirmedEmail[$i]->send_result = (object) array('success' => true, 'msg' => '');
              $sent                            = true;
            }
          } else {
            $sent                            = false;
            $confirmedEmail[$i]->send_result = (object) array('success' => false, 'msg' => 'Invalid email address');
          }
          $confirmedEmail[$i]->sent = $sent;
          if ((int) $confirmedEmail[$i]->target_type == 0) {
            $toBeUpdated['admin_email_sent'] = ($sent) ? 1 : 0;
          } else {
            $toBeUpdated['user_email_sent'] = ($sent) ? 1 : 0;
          }
        }

        if (!empty($adminErrors)) {
          $toBeUpdated['admin_email_notes'] = json_encode($adminErrors);
        }
        if (!empty($userErrors)) {
          $toBeUpdated['user_email_notes'] = json_encode($userErrors);
        }
        if (!empty($adminEmails)) {
          $toBeUpdated['admin_email'] = implode(', ', $adminEmails);
        }
        if (!empty($userEmails)) {
          $toBeUpdated['user_email'] = implode(', ', $userEmails);
        }
        $toBeUpdated = (object) $toBeUpdated;
        $this->db->updateObject('#__formea_submissions', $toBeUpdated, 'id');
      }
      $retObject->setSuccess(true);
      $retObject->setResult((object) [
        'confirmedEmails' => $confirmedEmail
      ]);
    } catch (Exception $e) {
      $retObject->setSuccess(false);
      $retObject->setMsg($e->getMessage());
    }

    return $retObject;
  }

  public function deleteSubmission()
  {
    $retObject = new FsrResponse();
    try {
      $container = Factory::getContainer();
      /** @var DatabaseDriver $db */
      $db    = $container->get('DatabaseDriver');
      $query = $db->getQuery(true);

      $conditions = array(
        $db->quoteName('submission_id') . ' = ' . $this->id,
      );
      $query->delete($db->quoteName('#__formea_submission_data'));
      $query->where($conditions);
      $db->setQuery($query);
      $db->execute();
      $query->clear();
      $conditions = array(
        $db->quoteName('id') . ' = ' . $this->id,
      );
      $query->delete($db->quoteName('#__formea_submissions'));
      $query->where($conditions);
      $db->setQuery($query);
      $db->execute();
      $query->clear();
      $retObject->setSuccess(true);
      $retObject->setResult([]);
    } catch (Exception $e) {
      $retObject->setMsg($e->getMessage());
    }

    return $retObject;
  }

  /**
   * @param   int[]  $groupIds
   * @param   array  $placeholders
   *
   * @return array
   * @since 1.2.1
   */
  public function getGroupsPlaceholders($submitted_data, $groupIds = [], $placeholders = [])
  {
    $db    = $this->db;
    $query = $db->getQuery(true);
    $query->select(['a.id', 'b.corename', 'b.params', 'b.group_id']);
    $query->from($db->quoteName('#__formea_groups', 'a'))->innerJoin(
      $db->quoteName('#__formea_group_cores', 'b') . ' ON ' . $db->quoteName('a.id') . ' = ' . $db->quoteName('b.group_id')
    );
    $query->where($db->quoteName('a.id') . ' IN (' . implode(',', $groupIds) . ')')
      ->where($db->quoteName('b.enabled') . ' = ' . $db->quote(1));
    $db->setQuery($query);
    $results = $db->loadObjectList();
    if (!empty($results)) {
      $totalResults = count($results);
      for ($i = 0; $i < $totalResults; $i++) {
        $className = 'Formea' . $results[$i]->corename;
        if (is_file(Path::clean(FORMEA_CORE_PATH . '/' . $results[$i]->corename . '/' . $className . '.php'))) {
          require_once FORMEA_CORE_PATH . '/' . $results[$i]->corename . '/' . $className . '.php';
          /** @var FormeaCore $core */
          $core = new $className(['group_id' => $results[$i]->group_id]);
          $placeholders = $core->processPlaceholder($submitted_data, $placeholders, ['params' => $results[$i]->params], $this->langTag);
        }
      }
    }

    return $placeholders;
  }
}
