<?php

namespace App\Services;

use App\Models\Component;
use Illuminate\Support\Facades\Log;
use Mtc\Modules\BlockRegistry\Models\BlockRegistry;
use Mtc\Modules\BlockRegistry\Services\BlockSyncService;
use Mtc\Modules\BlockRegistry\Services\EntityBlockService;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\Error\Error as TwigError;

class ComponentRendererService
{
    private Environment $twig;

    public function __construct()
    {
        $this->initializeTwigEnvironment();
    }

    /**
     * Render component with sample data
     */
    public function renderComponent(Component $component): string
    {
        if (!$component->is_renderable) {
            return $this->renderError($component->error_message ?? 'Component is not renderable');
        }

        try {
            // If this component is a registered block with authored example_data,
            // render it through the real block pipeline so the preview matches a
            // published instance. Falls back to inline dummy data otherwise.
            $blockExample = $this->renderBlockExample($component);
            if ($blockExample !== null) {
                return $blockExample;
            }

            // Components without example_data define their own dummy data inline.
            $sampleData = ['show_dummy_data' => true];
            $template = $this->twig->load('includes/' . $component->path);

            return $template->render($sampleData);

        } catch (TwigError $e) {
            $errorMessage = "Twig error in {$component->path}: " . $e->getMessage();
            Log::error($errorMessage);
            return $this->renderError($errorMessage);

        } catch (\Exception $e) {
            $errorMessage = "Rendering error in {$component->path}: " . $e->getMessage();
            Log::error($errorMessage);
            return $this->renderError($errorMessage);
        }
    }

    /**
     * If the component maps to a registered block that has authored
     * `example_data`, render it through the real block pipeline and return the
     * HTML. Returns null when the component is not a block, or has no
     * example_data, so the caller falls back to inline `show_dummy_data`.
     */
    private function renderBlockExample(Component $component): ?string
    {
        // The `template` column is stored inconsistently (some rows carry an
        // `includes/` prefix, some don't — see BlockRegistry::getTemplatePath()).
        // $component->path never has the prefix, so match both forms.
        $block = BlockRegistry::where('is_active', true)
            ->where(function ($query) use ($component) {
                $query->where('template', $component->path)
                    ->orWhere('template', 'includes/' . $component->path);
            })
            ->orderBy('order_index')
            ->orderBy('id')
            ->first();
        if (!$block) {
            return null;
        }

        if (!app(BlockSyncService::class)->hasExampleData($block->slug)) {
            return null;
        }

        // renderExample() returns '' (not null) when both the example_data and
        // its own inline show_dummy_data fallback fail. Treat that empty result
        // as "no preview" so renderComponent() falls through to its inline
        // show_dummy_data path rather than returning a blank.
        $rendered = app(EntityBlockService::class)->renderExample($block->slug);

        return $rendered !== '' ? $rendered : null;
    }

    /**
     * Get component with sample data for API response
     */
    public function getComponentWithSampleData(Component $component): array
    {
        // Simple approach: components define their own dummy data inline
        $sampleData = ['show_dummy_data' => true];
        $usage = [
            'include_example' => "{% include 'includes/{$component->path}' %}",
            'required_variables' => ['show_dummy_data'],
            'optional_variables' => ['All component-specific variables defined in the component file'],
        ];

        return [
            'component' => $component->toArray(),
            'sample_data' => $sampleData,
            'usage' => $usage,
        ];
    }

    /**
     * Render component preview page (full HTML)
     */
    public function renderComponentPreview(Component $component): string
    {
        $componentOutput = '';
        $errorMessage = null;

        if ($component->is_renderable) {
            try {
                $componentOutput = $this->renderComponent($component);
            } catch (\Exception $e) {
                $errorMessage = $e->getMessage();
            }
        } else {
            $errorMessage = $component->error_message;
        }

        $sampleData = ['show_dummy_data' => true];
        $usage = [
            'include_example' => "{% include 'includes/{$component->path}' %}",
            'required_variables' => ['show_dummy_data'],
            'optional_variables' => ['All component-specific variables defined in the component file'],
        ];

        return $this->renderPreviewHtml([
            'component' => $component,
            'componentOutput' => $componentOutput,
            'errorMessage' => $errorMessage,
            'sampleData' => $sampleData,
            'usage' => $usage,
        ]);
    }

    /**
     * Initialize Twig environment using main system's approach
     */
    private function initializeTwigEnvironment(): void
    {
        // Use the same Twig initialization pattern as the main system
        $path = base_path() . '/';
        $templatesPath = base_path('sites/default/templates');

        if (!is_dir($templatesPath)) {
            throw new \RuntimeException("Templates directory not found: $templatesPath");
        }

        // Initialize Twig loader with multiple template paths
        $coreTemplatesPath = base_path('core/templates');
        $loader = new FilesystemLoader([$templatesPath, $coreTemplatesPath]);

        // Create Twig environment with component-specific settings
        $this->twig = new Environment($loader, [
            'cache' => false, // Disable caching for component preview
            'debug' => config('app.debug', false),
            'strict_variables' => false, // Allow undefined variables for sample data
        ]);

        // Add debug extension if needed
        if (config('app.debug', false)) {
            $this->twig->addExtension(new \Twig\Extension\DebugExtension());
        }

        // The functions.twig.php file expects a global $twig variable
        global $twig;
        $twig = $this->twig;

        // Load the main system's Twig functions (includes file_get_contents, config, etc.)
        $functionsPath = $path . 'core/includes/functions.twig.php';
        if (!file_exists($functionsPath)) {
            throw new \RuntimeException("Functions file not found: $functionsPath");
        }

        include $functionsPath;

        // Add the same global variables as main system
        $this->addMainSystemGlobals();
    }

    /**
     * Add main system's global variables and any component-specific customizations
     */
    private function addMainSystemGlobals(): void
    {
        // Add the same global variables as the main system
        // Get all user defined settings (same as header.inc.php)
        $settings = get_defined_constants(true);
        $settings = $settings['user'];
        $this->twig->addGlobal('settings', $settings);

        // Add image folders global (components often use this)
        global $image_folders;
        if (isset($image_folders)) {
            $this->twig->addGlobal('image_folders', $image_folders);
        }

        // Vite functions (vite, vite_css) are already loaded via functions.twig.php

        // Load plugins and modules (same as main system)
        $this->loadPluginsAndModules();
    }

    /**
     * Load plugins and modules (same as main system)
     */
    private function loadPluginsAndModules(): void
    {
        $loaded_module_paths = [];
        $module_types = ['plugins', 'modules'];

        $previous_dir = getcwd();

        foreach ($module_types as $module_type) {
            $module_folder_parent = base_path() . '/' . $module_type . '/';

            if (is_dir($module_folder_parent)) {
                chdir($module_folder_parent);

                $modules = [];

                // Check if there is a user-defined module order
                if (file_exists('./.order')) {
                    $modules = file('./.order');
                    $modules = array_map('trim', $modules);
                    $modules = array_filter($modules, function ($module) {
                        return !empty($module);
                    });
                }

                // Add unlisted modules from the modules directory
                $modules = array_merge($modules, glob('*', GLOB_ONLYDIR));
                $modules = array_unique($modules);

                foreach ($modules as $module) {
                    $module_folder = $module_folder_parent . $module;

                    if (is_dir($module_folder) && $module != '.' && $module != '..') {
                        if (is_file($module_folder . '/loader.php')) {
                            $loaded_module_paths[] = $module_folder . '/loader.php';
                        }
                    }
                }
            }
        }

        chdir($previous_dir);

        // Load plugin functions manually since the global $twig approach doesn't work
        $this->registerPluginFunctions();
    }

    /**
     * Register plugin functions manually
     */
    private function registerPluginFunctions(): void
    {
        // Register ShareButtons follow_buttons function
        $this->twig->addFunction(new \Twig\TwigFunction('follow_buttons', function ($template = 'social/follow_buttons.twig') {
            // Use the ShareButtons class if available, otherwise return empty content for preview
            try {
                if (class_exists('\Mtc\Plugins\ShareButtons\Classes\ShareButtons')) {
                    $shareButtonsClass = '\Mtc\Plugins\ShareButtons\Classes\ShareButtons';
                    $follow_buttons = (new $shareButtonsClass())->where('hide', 0)->orderBy('order', 'ASC')->get();
                    return $this->twig->render($template, compact('follow_buttons'));
                } else {
                    // Fallback for component preview
                    return '<div class="social-buttons-preview">Social buttons would appear here</div>';
                }
            } catch (\Exception $e) {
                Log::error("Error rendering follow_buttons: " . $e->getMessage());
                return '<div class="social-buttons-preview">Social buttons would appear here</div>';
            }
        }));
    }

    /**
     * Render error message
     */
    private function renderError(string $message): string
    {
        return '<div class="component-render-error" style="background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 1rem; margin: 1rem 0; border-radius: 4px;">' .
               '<strong>Rendering Error:</strong> ' . htmlspecialchars($message) .
               '</div>';
    }

    /**
     * Render full HTML preview page
     */
    private function renderPreviewHtml(array $data): string
    {
        $component = $data['component'];
        $componentOutput = $data['componentOutput'];
        $errorMessage = $data['errorMessage'];
        $usage = $data['usage'];

        // Generate Vite asset URLs using shared functions from functions.twig.php
        $jsUrl = '';
        $cssUrls = [];
        $viteFunction = $this->twig->getFunction('vite');
        $viteCssFunction = $this->twig->getFunction('vite_css');
        if ($viteFunction) {
            $jsUrl = $viteFunction->getCallable()('js/app.js');
        }
        if ($viteCssFunction) {
            $cssUrls = $viteCssFunction->getCallable()('js/app.js');
        }

        // Generate CSS link tags
        $cssLinks = '';
        foreach ($cssUrls as $url) {
            $cssLinks .= '    <link href="' . htmlspecialchars($url) . '" rel="stylesheet">' . "\n";
        }

        $html = '<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Component Preview: ' . htmlspecialchars($component->name) . '</title>
' . $cssLinks . '    <style>
        body {
            font-family: system-ui, -apple-system, sans-serif;
            line-height: 1.5;
            margin: 0;
            padding: 0;
            background: #f8f9fa;
        }
        #vue_environment {
            padding: 2rem;
        }
        .component-preview {
            margin: 0 auto;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .component-info {
            padding: 2rem;
            border-bottom: 1px solid #e9ecef;
            background: #f8f9fa;
        }
        .component-info h1 {
            margin: 0 0 0.5rem 0;
            color: #212529;
        }
        .component-info p {
            margin: 0 0 2rem 0;
            color: #6c757d;
        }
        .component-info h2 {
            margin: 0 0 1rem 0;
            font-size: 1.25rem;
            color: #495057;
        }
        .component-info pre {
            background: #f8f9fa;
            border: 1px solid #dee2e6;
            border-radius: 4px;
            padding: 1rem;
            overflow-x: auto;
            font-size: 0.875rem;
        }
        .component-output {
            padding: 2rem;
        }
        .component-output h3 {
            margin: 0 0 1rem 0;
            color: #495057;
        }
        .component-error {
            padding: 2rem;
            background: #f8d7da;
            border-left: 4px solid #dc3545;
        }
        .component-error h1 {
            color: #721c24;
            margin: 0 0 1rem 0;
        }
        .component-error p {
            margin: 0.5rem 0;
        }
        .component-error pre {
            background: #f5c6cb;
            border: 1px solid #f1aeb5;
            border-radius: 4px;
            padding: 1rem;
            margin: 1rem 0;
            white-space: pre-wrap;
            font-size: 0.875rem;
        }
    </style>
</head>
<body>
<div id="vue_environment">';

        if ($errorMessage) {
            $html .= '
    <div class="component-error">
        <h1>Rendering Error</h1>
        <p><strong>Component:</strong> ' . htmlspecialchars($component->path) . '</p>
        <p><strong>Error:</strong> ' . htmlspecialchars($errorMessage) . '</p>
    </div>';
        } else {
            $html .= '
    <div class="component-preview">
        <div class="component-info">
            <h1>' . htmlspecialchars($component->name) . '</h1>
            <p>' . htmlspecialchars($component->description) . '</p>

            <h2>Usage</h2>
            <pre><code>' . htmlspecialchars($usage['include_example']) . '</code></pre>';

            if (!empty($usage['required_variables'])) {
                $html .= '<p><strong>Required variables:</strong> ' . implode(', ', array_map('htmlspecialchars', $usage['required_variables'])) . '</p>';
            }

            if (!empty($usage['optional_variables'])) {
                $html .= '<p><strong>Optional variables:</strong> ' . implode(', ', array_map('htmlspecialchars', $usage['optional_variables'])) . '</p>';
            }

            $html .= '
        </div>

        <div class="component-output">
            <h3>Component Preview</h3>
            ' . $componentOutput . '
        </div>
    </div>';
        }

        $html .= '
</div>
    <script src="' . htmlspecialchars($jsUrl) . '" type="module"></script>
</body>
</html>';

        return $html;
    }
}