<?php
  /**
   * @version     1.0.3
   * @package     Joomla 4
   * @subpackage  Formea
   * @author      Feseur Sdn Bhd
   * @copyright   Copyright (C) 2010 - 2020 Feseur Sdn Bhd
   * @license     GNU/GPL, see LICENSE.php
   */


  defined('_JEXEC') or die();

  // no direct access
  use Feseur\Library\FsrHelper;
  use Feseur\Library\FsrResponse;
  use GuzzleHttp\Client;
  use Joomla\CMS\Factory;
  use Joomla\CMS\Language\Text;
  use Joomla\CMS\Uri\Uri;
  use Joomla\CMS\WebAsset\WebAssetManager;
  use Joomla\Component\Formea\Plugins\Core\Pdf\FormeaMainPdf;
  use Joomla\Component\Formea\Site\Helper\FormeaGeneralHelper;
  use Joomla\Component\Formea\Site\Libraries\FormeaCore;
  use Joomla\Component\Formea\Site\Libraries\FormeaSubmissionResponse;
  use Joomla\Database\DatabaseDriver;
  use Joomla\Filesystem\File;
  use Joomla\Filesystem\Folder;
  use Joomla\Filesystem\Path;
  use Joomla\Registry\Registry;
  use Joomla\Session\SessionInterface;

  class FormeaPdf extends FormeaCore
  {
    private $corePath;
    private $core;

    private $enabled = false;
    private $app;

    public function __construct($config=[])
    {
      parent::__construct($config);
      $this->corePath = JPATH_ROOT . '/components/com_formea/plugins/core/Pdf/';
      $this->app      = Factory::getApplication();
      /** @var WebAssetManager $wa */
      $wa       = $this->app->getDocument()->getWebAssetManager();
      $registry = $wa->getRegistry();
      $registry->addRegistryFile('components/com_formea/plugins/core/Pdf/joomla.asset.json');

      $enabled       = filter_var((int) $this->formParams->get('enabled', 0), FILTER_VALIDATE_BOOLEAN);
      $this->enabled = $enabled;
    }


    protected function getFormParam()
    {
      if (empty($this->core))
      {
        $container = Factory::getContainer();
        /** @var DatabaseDriver $db */
        $db    = $container->get('DatabaseDriver');
        $query = $db->getQuery(true);
        $query->select(['a.*', 'b.params AS coreParams']);
        $query->from($db->quoteName('#__formea_form_cores', 'a'));
        $query->innerJoin($db->quoteName('#__formea_cores', 'b') . ' ON ' .
          $db->quoteName('a.corename') . ' = ' . $db->quoteName('b.name')
        );
        $query->where($db->quoteName('a.form_id') . ' = ' . $db->quote($this->formId));
        $query->where($db->quoteName('a.corename') . ' = ' . $db->quote('Pdf'));
        $query->where($db->quoteName('b.state') . ' = ' . $db->quote(1));
        $db->setQuery($query);
        $core = $db->loadObject();
        if (!empty($core))
        {
          $core->coreParams = new Registry($core->coreParams);
          $core->params     = new Registry($core->params);
        }
        $this->core = $core;
      }

      return $this->core;
    }



    /*public function onBeforeStoreSubmission($submission)
    {


      return $submission;
    }*/


    /**
     * Method called right after form has been submitted and gone through validation. Not necessarily stored in DB if
     * contains validation error
     *
     * @param   FormeaSubmissionResponse  $submissionResponse
     *
     * @return FormeaSubmissionResponse
     * @since 1.0.0
     */
    public function onAfterSubmission($submissionResponse)
    {
      if ($this->enabled)
      {
        if (isset($submissionResponse->submission) && !empty($submissionResponse->submission))
        {
          $elements = $submissionResponse->elements;
          if (!empty($elements) && isset($elements[0]))
          {
            $coreObject = $this->getFormParam();
            $pages      = $coreObject->params->get('pdf_pages', null);
            if (!empty($pages))
            {
              require_once __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'FormeaMainPdf.php';
              $generatePdf = $this->generatePdf($coreObject->params, false, $submissionResponse);
              if (isset($generatePdf['file_name']) && isset($generatePdf['link_path']) && isset($generatePdf['dir_path']))
              {
                $submission = $submissionResponse->submission;
                $upd        = [
                  'form_id'       => $submission->form_id,
                  'submission_id' => $submission->id,
                  'setIndex'      => -1,
                  'group_id'      => 0,
                  'is_link'       => 1,
                  'field_name'    => 'PDFGEN',
                  'field_text'    => 'Generated PDF',
                  'field_caption' => 'Generated PDF',
                  'field_value'   => $generatePdf['file_name'],
                  'link_path'     => json_encode($generatePdf['link_path']),
                  'dir_path'      => json_encode($generatePdf['dir_path']),
                ];
                $upd        = (object) $upd;
                $container  = Factory::getContainer();
                /** @var DatabaseDriver $db */
                $db = $container->get('DatabaseDriver');
                $db->insertObject('#__formea_submission_data', $upd);
              }
            }
          }
        }
      }

      return $submissionResponse;
    }

    /**
     * @param $contentObject
     * @param $langTag
     *
     *
     * @return string
     * @since 1.0.0
     */
    private function getPageContent($contentObject, $langTag)
    {
      $content = "";
      $langTag = str_replace('-', '_', $langTag);
      if (isset($contentObject->{$langTag}))
      {
        if (!empty($contentObject->{$langTag}) && strlen($contentObject->{$langTag}) > 0)
        {
          $content = $this->fixImageUrls($contentObject->{$langTag});
        }
      }

      return $content;
    }

    public function generateTestPdf($args = [])
    {
      if (isset($args['pages']))
      {
        $params = new Registry($args);
        $this->generatePdf($params,true);
      }
    }

    /**
     * @param   Registry                       $params
     * @param   boolean                        $preview
     * @param   FormeaSubmissionResponse|null  $submissionResponse
     *
     * @return mixed
     * @since 1.0.0
     */
    private function generatePdf($params, $preview = true, $submissionResponse = null)
    {

      $doc_author      = $params->get('doc_author', '');
      $doc_title       = $params->get('doc_title', '');
      $doc_subject     = $params->get('doc_subject', '');
      $doc_keywords    = $params->get('doc_keywords', '');
      $doc_font        = $params->get('doc_font', 'helvetica');
      $file_name       = $params->get('file_name', 'myPdf.pdf');
      $uploadDirectory = $params->get('upload_path', 'media/com_formea/generated/pdf');
      $doc_font_size   = (int) $params->get('doc_font_size', 10);
      $pages           = $params->get('pages', []);
      $placeholders    = [];
      $submission      = null;
      $proceed         = false;
      if ($preview)
      {
        $proceed      = true;
        $doc_author   .= ' PREVIEW';
        $doc_title    .= ' PREVIEW';
        $doc_subject  .= ' PREVIEW';
        $doc_keywords .= ' PREVIEW';
        $file_name    .= ' PREVIEW';
      }
      elseif (!$preview && !empty($submissionResponse))
      {

        $elements = $submissionResponse->elements;
        if (!empty($elements) && isset($elements[0]))
        {
          $proceed = true;
          $_pages  = $params->get('pdf_pages', []);
          $pages   = [];
          foreach ($_pages as $page)
          {
            $pages[] = json_decode(json_encode($page), true);
          }

          $formAlias        = $elements[0]->form_alias;
          $submission       = $submissionResponse->submission;
          $formeaSubmission = new \Joomla\Component\Formea\Site\Libraries\FormeaSubmission($submission->id, [
            'langTag' => $submission->language
          ]);
          $placeholders     = $formeaSubmission->processPlaceHolders($submission->submitted_url);
          $file_name        = str_replace('.pdf', '', $file_name);
          if (!empty($prefix))
          {
            $file_name = $prefix . $file_name;
          }
          $file_name = File::makeSafe($file_name);
          $file_name = \Joomla\CMS\Filter\OutputFilter::stringURLSafe($file_name);
          foreach ($placeholders as $key => $value)
          {
            $key             = strtoupper($key);
            $file_name       = str_replace('[' . $key . ']', $value, $file_name ?? '');
            $uploadDirectory = str_replace('[' . $key . ']', $value, $uploadDirectory ?? '');
          }

          $uploadDirectory = rtrim($uploadDirectory, '/');
          $uploadDirectory = $uploadDirectory . '/' . $formAlias . '/' . $submission->id;
          $uploadDirectory = JPATH_ROOT . '/' . $uploadDirectory;
          if (!is_dir(Path::clean($uploadDirectory)))
          {
            Folder::create($uploadDirectory);
          }
          if (is_file(Path::clean($uploadDirectory . '/' . $file_name . '.pdf')))
          {
            $file_name .= '-' . uniqid();
          }
          $file_name .= '.pdf';
        }
      }

      if ($proceed)
      {
        $pdf = new FormeaMainPdf(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
        $pdf->setCreator(Uri::root() . ' | Formea Form Builder');
        if (!empty($doc_author))
        {
          $pdf->setAuthor($doc_author);
        }

        if (!empty($doc_subject))
        {
          $pdf->setSubject($doc_subject);
        }

        if (!empty($doc_title))
        {
          $pdf->setTitle($doc_title);
          $pdf->setViewerPreferences(['DisplayDocTitle' => true]);
        }

        if (!empty($doc_keywords))
        {
          $pdf->setKeywords($doc_keywords);
        }

        $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
        // set font
        $pdf->SetFont($doc_font, '', $doc_font_size);
       // $pdf->SetCellPadding(0);
        $tagvs = array('p' => array(0 => array('h' => 0, 'n' => 0), 1 => array('h' => 0, 'n' => 0)));
        //$pdf->setHtmlVSpace($tagvs);
        $pdf->setCellHeightRatio(1);

        $pdf->setPrintHeader(false);
        $pdf->setPrintFooter(false);
        $langTag    = $this->app->getLanguage()->getTag();
        $hasContent = false;

        foreach ($pages as $page)
        {
          $content = null;

          if ($preview)
          {
            $contentObject = [];
            foreach ($page['pdf_content'] as $pdfContent)
            {
              $contentObject[$pdfContent['langTag']] = $pdfContent['content'];
            }
            $content = $this->getPageContent((object) $contentObject, $langTag);
          }
          elseif (!empty($submission))
          {
            $content = $this->getPageContent((object) $page['pdf_content'], $submission->language);
            foreach ($placeholders as $key => $value)
            {
              $key     = strtoupper($key);
              $content = str_replace('[' . $key . ']', $value, $content ?? '');
            }
          }

          if (!empty($content))
          {
            $hasContent   = true;
            $paperSetting = $page['paper_setting'];
            $margins      = $page['margins'];
            $orientation  = $paperSetting['orientation'];

            $pdf->SetMargins((float) $margins['left'], (float) $margins['top'], (float) $margins['right']); // Left, Top, Right margins
            if ((float) $margins['bottom'] < 0.1)
            {
              $pdf->SetAutoPageBreak(false); // Disable auto page break to ensure no bottom margin
            }
            else
            {
              $pdf->SetAutoPageBreak(true, (float) $margins['bottom']);
            }
            if ($orientation == 'custom')
            {
              $paperWidth  = (float) $paperSetting['paper_width'];
              $paperHeight = (float) $paperSetting['paper_height'];
              $orientation = $this->getOrientation($paperWidth, $paperHeight);
              $pdf->AddPage($orientation, array($paperWidth, $paperHeight));
            }
            else
            {
              $pdf->AddPage($orientation, $paperSetting['paper_type']);
            }
            $page_bg_image_enabled = (int) $page['page_bg_image_enabled'];
            $page_bg_image         = $page['page_bg_image'];
            if ($page_bg_image_enabled > 0 && strlen($page_bg_image) > 4)
            {
              $analuzeUrl = $this->analyzeUrl($page_bg_image);
              if (!$analuzeUrl['isAbsolute'])
              {
                $page_bg_image = FsrHelper::getImageSrc($page_bg_image);
                $page_bg_image = Uri::root() . $page_bg_image;
              }

              // get the current page break margin
              $bMargin = $pdf->getBreakMargin();
              // get current auto-page-break mode
              $auto_page_break = $pdf->getAutoPageBreak();
              // disable auto-page-break
              $pdf->SetAutoPageBreak(false, 0);

              $pdf->Image($page_bg_image, 0, 0, $pdf->getPageWidth(), $pdf->getPageHeight(), '', '', '', false, 300, '', false, false, 0);

              // restore auto-page-break status
              $pdf->SetAutoPageBreak($auto_page_break, $bMargin);
              // set the starting point for the page content
              $pdf->setPageMark();

            }
            $colors = $page['colors'];
            if (strlen($colors['bg']) > 3)
            {
              $BgRgbColor = $this->hexToRgb($colors['bg']);
              $pdf->SetFillColor($BgRgbColor[0], $BgRgbColor[1], $BgRgbColor[2]);
              // Draw a rectangle with the fill color
              $pdf->Rect(0, 0, $pdf->getPageWidth(), $pdf->getPageHeight(), 'F');
            }
            if (strlen($colors['text']) > 3)
            {
              $textRgbColor = $this->hexToRgb($colors['text']);
              $pdf->SetTextColor($textRgbColor[0], $textRgbColor[1], $textRgbColor[2]);
            }
            else
            {
              $pdf->SetTextColor(0, 0, 0);
            }

            $pdf->WriteHTML($content, true, 0, true, 0);
            // reset pointer to the last page
            $pdf->lastPage();
          }
        }

        if ($hasContent)
        {
          if ($preview)
          {
            $file_name = File::makeSafe($file_name);
            $file_name = \Joomla\CMS\Filter\OutputFilter::stringURLSafe($file_name);
            //Close and output PDF document
            $pdf->Output($file_name . '.pdf', 'D');
            $this->app->setHeader('Content-Type', 'application/pdf;', true);
            $this->app->setHeader('Content-disposition', 'attachment; filename="' . $file_name . '.pdf"', true);
            $this->app->setHeader('Cache-Control', 'no-cache', true);
            $this->app->sendHeaders();
            $this->app->close();
          }
          else
          {
            $pdf->Output($uploadDirectory . '/' . $file_name, 'F');
            $linkPath = Uri::root() . trim($uploadDirectory, '/') . '/' . $file_name;
            $linkPath = [$linkPath];
            $dir_path = [
              str_replace(JPATH_ROOT . '/', '', $uploadDirectory . DIRECTORY_SEPARATOR . $file_name),
            ];

            return [
              'file_name' => $file_name,
              'link_path' => $linkPath,
              'dir_path'  => $dir_path,
            ];
          }
        }

      }

      return false;
    }

    private function getOrientation($width, $height)
    {
      if ($width > $height)
      {
        return 'L';
      }
      else
      {
        return 'P';
      }
    }

    private function hexToRgb($hex)
    {
      $hex = str_replace('#', '', $hex);

      if (strlen($hex) == 6)
      {
        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));
      }
      elseif (strlen($hex) == 3)
      {
        $r = hexdec(str_repeat(substr($hex, 0, 1), 2));
        $g = hexdec(str_repeat(substr($hex, 1, 1), 2));
        $b = hexdec(str_repeat(substr($hex, 2, 1), 2));
      }
      else
      {
        return false; // Invalid hex code
      }

      return array($r, $g, $b);
    }

    private function analyzeUrl($url)
    {
      // Check if the URL is absolute or relative
      $isAbsolute = preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|mailto:|data:)/i', $url);

      // Check if the URL uses HTTP or HTTPS
      $isHttp = preg_match('/^(http:\/\/|https:\/\/)/i', $url);

      return [
        'isAbsolute' => $isAbsolute,
        'isHttp'     => $isHttp
      ];
    }

    /**
     * @param $html
     *
     * @return false|string
     *
     * @since version
     */
    private function fixImageUrls($html)
    {
      $dom = new DOMDocument();
      // Suppress errors due to malformed HTML by using @
      @$dom->loadHTML($html);

      $xpath  = new DOMXPath($dom);
      $images = $xpath->query('//img');

      foreach ($images as $image)
      {
        $src = $image->getAttribute('src');

        // Check if the src attribute starts with http or https
        if (!preg_match('/^(http:\/\/|https:\/\/)/i', $src))
        {
          $cleanedImage = FsrHelper::getImageSrc($src);
          if (!empty($cleanedImage))
          {
            // Prepend http:// if it doesn't have a scheme
            $src = Uri::root() . ltrim($cleanedImage, '/');
          }
          else
          {
            $src = Uri::root() . ltrim($src, '/');
          }

          $image->setAttribute('src', $src);
        }
      }

      // Save the modified HTML
      // return $dom->saveHTML();
      // Extract the inner HTML of the body or the root element
      $body = $dom->getElementsByTagName('body')->item(0);
      if ($body)
      {
        $innerHtml = '';
        foreach ($body->childNodes as $child)
        {
          $innerHtml .= $dom->saveHTML($child);
        }

        return $innerHtml;
      }

      return '';
    }

  }
