<?php
/**
 * @package     MefisAssetBridge
 * @subpackage  Joomla_Administrator_Component
 *
 * @copyright   Copyright (C) 2025 Goran Usljebrka. All rights reserved.
 * @license     Proprietary — No resale or incorporation into other projects without explicit written permission. see LICENSE.txt
 */

namespace Mefi\Component\MefisAssetBridge\Administrator\View\Preview;

defined('_JEXEC') or die;

use function YOOtheme\app;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Uri\Uri;
use Joomla\Registry\Registry;
use Mefi\Component\MefisAssetBridge\Administrator\Helper\AssetPreviewHelper;
use MefisAssetBridgeCore\DTO\AuthenticatedUserDto;
use YOOtheme\Application;

class RawView extends BaseHtmlView
{
    use \MefisAssetBridgeCore\Traits\Encryptor;

    protected $renderedEl;
    protected $baseUrl;
    protected $downloadStatus;
    protected $captureId;

    public function display($tpl = null)
    {

        // error_reporting(E_ALL & ~E_DEPRECATED);
        // disable error reporting
        error_reporting(0);

        $yoothemeTemplatePath = JPATH_SITE . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'yootheme';
        $yoothemeTemplateChildPath = false;
        $app   = Factory::getApplication();
        $input = $app->input;

        $session    = Factory::getSession();
        $this->css  = [];

        // Read captureId from URL.
        $captureIdFromUrl = preg_replace('/[^a-f0-9]/', '', trim($input->getString('captureId', '')));

        // Derive the user UUID from the same auth session that every controller
        // already uses — no need for a separate previewUserUuid key.
        $userUuid  = '';
        $masterKey = '';
        try {
            $authData = $session->get('mefisAssetBridge.auth', null);
            if (!empty($authData)) {
                $userDto   = ($authData instanceof AuthenticatedUserDto)
                    ? $authData
                    : AuthenticatedUserDto::fromArray($authData);
                $userUuid  = (string) $userDto->getUser()->getUserUuid();
                $masterKey = (string) $userDto->getMasterKey();
            }
        } catch (\Throwable $ignored) {}

        // Build the expected preview file path. The file is written synchronously
        // (file_put_contents) in setPreview() before the HTTP response is sent, so
        // file_exists() has no race condition — unlike the session captureId, which
        // is committed during $app->close() after the response buffer is already flushed.
        $previewFile = (!empty($captureIdFromUrl) && !empty($userUuid))
            ? JPATH_PUBLIC
                . DIRECTORY_SEPARATOR . 'media'
                . DIRECTORY_SEPARATOR . 'plg_system_mefisassetbridge'
                . DIRECTORY_SEPARATOR . 'preview_cache'
                . DIRECTORY_SEPARATOR . $userUuid
                . DIRECTORY_SEPARATOR . $captureIdFromUrl . '.json'
            : null;

        // Validate: the file must exist (proves this captureId was issued for this
        // user's current request) and the userUuid must come from the authenticated session.
        $captureIdValid = !empty($captureIdFromUrl)
            && !empty($userUuid)
            && $previewFile !== null
            && file_exists($previewFile);

        $canDownload        = $session->get('mefisAssetBridge.previewcache', false);
        $shouldDownload     = (bool) $session->get('mefisAssetBridge.previewdownload', true);
        $downloadStatusJson = $session->get('mefisAssetBridge.previewstatus', '{}');

        $this->downloadStatus = json_decode($downloadStatusJson, true);
        $this->captureId      = $captureIdValid ? $captureIdFromUrl : '';

        // Load and decrypt asset data from the per-user, per-capture file.
        if ($captureIdValid && !empty($masterKey)) {
            $this->setEncryptorKey($masterKey);
            $rawContent = (string) file_get_contents($previewFile);
            $assetData  = $this->decrypt($rawContent) ?? '{}';
        } else {
            $assetData = '{}';
        }


        $p = explode('/', rtrim(Uri::base(), '/'));
        foreach ($p as $i => $part) {
            if ($part === 'administrator') {
                unset($p[$i]);
                break;
            }
        }
        $this->baseUrl = implode('/', $p) . '/';

        // Get YOOtheme (template) config from database
        $db    = Factory::getContainer()->get('DatabaseDriver');
        $query = $db->getQuery(true)
            ->select([$db->quoteName('id'), $db->quoteName('params')])
            ->from($db->quoteName('#__template_styles'))
            ->where($db->quoteName('client_id') . ' = 0')
            ->where($db->quoteName('home') . ' = 1')
            ->where($db->quoteName('template') . ' = ' . $db->quote('yootheme'));

        $db->setQuery($query);

        try {
            $templateStyle = $db->loadObject();

            if (empty($templateStyle)) {
                throw new \RuntimeException('YOOtheme template not found or not set as default.');
            }

            $templateStyleId = $templateStyle->id;
            $templateParams  = new Registry($templateStyle->params);

            // Get 'config' parameter from JSON
            $yoothemeConfigJson = $templateParams->get('config', '{}');
            $yoothemeConfig     = json_decode($yoothemeConfigJson, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new \RuntimeException('Failed to decode YOOtheme config JSON: ' . json_last_error_msg());
            }
        } catch (\Exception $e) {
            $templateStyleId = null;
            $yoothemeConfig  = [];
        }

        $mediaFolder = false;
        if (isset($yoothemeConfig['media_folder'])) {
            $mediaFolder = $yoothemeConfig['media_folder'];
        }
        $childTheme = false;
        if (isset($yoothemeConfig['child_theme'])) {

            if (is_dir(JPATH_SITE . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'yootheme_' . $yoothemeConfig['child_theme'])) {
                $childTheme = [
                    'name' => $yoothemeConfig['child_theme'],
                    'path' => JPATH_SITE . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'yootheme_' . $yoothemeConfig['child_theme'],
                ];

                $yoothemeTemplateChildPath = $childTheme['path'];
            }
        }

        // enqueue assets
        if ($templateStyleId) {

            // check is there theme.{styleId}.css in child theme
            if ($yoothemeTemplateChildPath && file_exists($yoothemeTemplateChildPath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'theme.' . $templateStyleId . '.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme_' . $childTheme['name'] . '/css/theme.' . $templateStyleId . '.css';

                // check is there theme.css in child theme
            } elseif ($yoothemeTemplateChildPath && file_exists($yoothemeTemplateChildPath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'theme.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme_' . $childTheme['name'] . '/css/theme.css';

                // check is there theme.{styleId}.css in main theme
            } elseif (file_exists($yoothemeTemplatePath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'theme.' . $templateStyleId . '.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme/css/theme.' . $templateStyleId . '.css';
                // check is there theme.css in main theme
            } elseif (file_exists($yoothemeTemplatePath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'theme.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme/css/theme.css';
            }

            // check is there custom.css in child theme
            if ($yoothemeTemplateChildPath && file_exists($yoothemeTemplateChildPath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'custom.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme_' . $childTheme['name'] . '/css/custom.css';
                // check is there custom.css in main theme
            } elseif (file_exists($yoothemeTemplatePath . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . 'custom.css')) {
                $this->css[] = $this->baseUrl . 'templates/yootheme/css/custom.css';
            }
        }

        try {

            $yoothemeBootstrap = JPATH_SITE . '/templates/yootheme/bootstrap.php';

            if (! file_exists($yoothemeBootstrap)) {
                throw new \RuntimeException('YOOtheme bootstrap not found: ' . $yoothemeBootstrap);
            }

            /** @var \YOOtheme\Application $yooapp */
            $yooapp = require $yoothemeBootstrap;
            $yooapp->load('~theme/packages/platform-joomla/bootstrap.php');
            $yooapp->load('~theme/packages/builder/bootstrap.php');
            $yooapp->load('~theme/packages/theme/bootstrap.php');

            /** @var \YOOtheme\Builder $builder */
            $builder = $yooapp(\YOOtheme\Builder::class);

            $this->renderedEl = $builder->render($assetData, ['prefix' => 'el', 'context' => 'render']);

            // Process the rendered HTML to cache any remaining remote assets.
            // Use a per-user subdirectory to prevent cross-user file conflicts.
            $cacheSubdir = $captureIdValid
                ? $userUuid
                : 'legacy';
            $mediaCacheDir = JPATH_PUBLIC
                . DIRECTORY_SEPARATOR . 'media'
                . DIRECTORY_SEPARATOR . 'plg_system_mefisassetbridge'
                . DIRECTORY_SEPARATOR . 'preview_cache'
                . DIRECTORY_SEPARATOR . $cacheSubdir;
            if (! is_dir($mediaCacheDir)) {
                mkdir($mediaCacheDir, 0755, true);
            }
            $mediaCacheUrl = $this->baseUrl . 'media/plg_system_mefisassetbridge/preview_cache/' . $cacheSubdir;

            if ($shouldDownload && $canDownload) {
                $this->renderedEl = AssetPreviewHelper::processHtmlForCaching($this->renderedEl, $mediaCacheDir, $mediaCacheUrl);
            } else {
                // strip remote elements if we are supposed to download them but are not allowed to
                if ($shouldDownload) {
                    $this->renderedEl = AssetPreviewHelper::stripRemoteAssetsFromHtml($this->renderedEl);
                }
            }

        parent::display($tpl);

        } catch (\Throwable $th) {
            echo 'Error rendering YOOtheme content: ' . $th->getMessage();
        }
    }

    public function getCss() {
        foreach($this->css as $css) {
            echo '<link rel="stylesheet" href="' . $css . '">' . "\n";
        }
    }
}
