<?php

declare(strict_types=1);

namespace CloudXM\SDK\Support;

use CloudXM\SDK\Support\HasLogger;
use CloudXM\SDK\Templates\TemplateRendererInterface;
use CloudXM\SDK\Contracts\ConfigurationInterface;

/**
 * Template Renderer Service
 *
 * Centralizes template loading and rendering with proper error handling
 * Follows SOLID principles and dependency injection pattern
 */
class TemplateRenderer implements TemplateRendererInterface
{
    use HasLogger;

    private array $shared = [];
    private string $templatePath;

    public function __construct(
        private ?ConfigurationInterface $config = null,
        ?string $templatePath = null
    ) {
        $this->templatePath = $templatePath ?? $this->getDefaultTemplatePath();
    }

    /**
     * Render a template with data
     *
     * @param string $template Template path relative to templates directory (without .php)
     * @param array $data Data to extract into template variables
     * @throws \RuntimeException If template file doesn't exist
     */
    public function render(string $template, array $data = []): void
    {
        $file = $this->resolveTemplatePath($template);

        if (!file_exists($file)) {
            $this->log()->error('sdk.template.not_found', [
                'template' => $template,
                'resolved_path' => $file,
                'search_path' => $this->templatePath,
                'caller' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? 'unknown'
            ]);

            throw new \RuntimeException(
                sprintf(__('Template file not found: %s', 'cloudxm-sdk'), $template)
            );
        }

        // Extract data to variables with EXTR_SKIP to prevent overwriting
        extract($data, EXTR_SKIP);

        // Include template
        include $file;
    }

    /**
     * Render template and return as string
     *
     * @param string $template Template path
     * @param array $data Data for template
     * @return string Rendered template content
     */
    public function fetch(string $template, array $data = []): string
    {
        ob_start();
        try {
            $this->render($template, $data);
            return ob_get_clean();
        } catch (\Exception $e) {
            ob_end_clean();
            throw $e;
        }
    }

    /**
     * Check if template exists
     */
    public function exists(string $template): bool
    {
        $file = $this->resolveTemplatePath($template);
        return file_exists($file);
    }

    /**
     * Get template modification time
     */
    public function getModificationTime(string $template): ?int
    {
        $file = $this->resolveTemplatePath($template);
        return file_exists($file) ? filemtime($file) : null;
    }

    /**
     * Resolve template path
     */
    private function resolveTemplatePath(string $template): string
    {
        // Remove leading slash and .php extension if present
        $template = ltrim($template, '/');
        $template = preg_replace('/\.php$/', '', $template);

        return $this->templatePath . '/' . $template . '.php';
    }

    /**
     * Get default template path
     * Uses ConfigurationInterface to calculate plugin template directory
     */
    private function getDefaultTemplatePath(): string
    {
        if ($this->config) {
            // Calculate template path from plugin file path
            $pluginPath = dirname($this->config->getPluginFilePath());
            return $pluginPath . '/templates';
        }

        // Fallback for SDK - should not be used in production plugins
        return dirname(__DIR__, 2) . '/templates';
    }

    /**
     * Share data across all templates
     */
    public function share(string $key, mixed $value): self
    {
        $this->shared[$key] = $value;
        return $this;
    }

    /**
     * Get configured template path
     */
    public function getTemplatePath(): string
    {
        return $this->templatePath;
    }
}