<?php

namespace Storeplugin\PDFInvoice\App;

defined('ABSPATH') || exit;

class TemplateLoader {

    /**
     * Template scope constants.
     */
    public const SCOPE_INVOICE = 'invoice';
    public const SCOPE_PACKING_SLIPS = 'packing-slips';

    /**
     * Template directories by scope.
     *
     * @var array<string, string>
     */
    private const TEMPLATE_DIRS = [
        self::SCOPE_INVOICE => NXTPDF_DIR . '/templates/invoice',
        self::SCOPE_PACKING_SLIPS => NXTPDF_DIR . '/templates/packing-slips',
    ];
    private const LEGACY_INVOICE_TEMPLATE_DIR = NXTPDF_DIR . '/templates';

    /**
     * Load and render a template file
     *
     * @param string $template Template name (e.g., 'default', 'modern', 'elegant')
     * @param array  $args     Data to pass to the template
     * @param bool   $return   Whether to return the output instead of echoing.
     * @param string $scope    Template scope (`invoice` or `packing-slips`).
     * @return string|void     Returns HTML string if $return is true
     */
    public static function view(string $template, array $args = [], bool $return = false, string $scope = self::SCOPE_INVOICE) {
        $template_file = self::resolveTemplateFile($template, $scope);

        if (!file_exists($template_file)) {
            if ($return) {
                return '<!-- Template not found: ' . esc_html($template) . '.php (scope: ' . esc_html($scope) . ') -->';
            }
            echo esc_html("Template not found: {$template}.php");
            return;
        }

        // Extract args to make them available as variables in the template.
        // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
        extract($args, EXTR_SKIP);

        if ($return) {
            ob_start();
            include $template_file;
            return ob_get_clean();
        }

        include $template_file;
    }

    /**
     * Get available templates
     *
     * @return array Array of template names (without .php extension)
     */
    public static function get_templates(string $scope = self::SCOPE_INVOICE): array {
        $templates = [];

        foreach (self::getTemplateDirs($scope) as $templateDir) {
            if (!is_dir($templateDir)) {
                continue;
            }

            $files = glob($templateDir . '/*.php');
            foreach ($files as $file) {
                $template = basename($file, '.php');
                if (strpos($template, '_') === 0) {
                    continue;
                }
                $templates[$template] = $template;
            }
        }

        return array_values($templates);
    }

    /**
     * Check if a template exists
     *
     * @param string $template Template name
     * @param string $scope    Template scope (`invoice` or `packing-slips`).
     * @return bool
     */
    public static function exists(string $template, string $scope = self::SCOPE_INVOICE): bool {
        $templateSlug = sanitize_file_name($template);
        if ($templateSlug === '') {
            return false;
        }

        foreach (self::getTemplateDirs($scope) as $templateDir) {
            if (file_exists($templateDir . '/' . $templateSlug . '.php')) {
                return true;
            }
        }

        return false;
    }

    /**
     * Resolve the final template slug after fallback handling.
     */
    public static function resolveTemplateSlug(string $template, string $scope = self::SCOPE_INVOICE): string
    {
        return basename(self::resolveTemplateFile($template, $scope), '.php');
    }

    /**
     * Resolve the stylesheet path paired with the selected template.
     */
    public static function resolveTemplateStylesheet(string $template, string $scope = self::SCOPE_INVOICE): string
    {
        $templateFile = self::resolveTemplateFile($template, $scope);
        $templateStylesheet = preg_replace('/\.php$/', '.css', $templateFile);

        if (is_string($templateStylesheet) && file_exists($templateStylesheet)) {
            return $templateStylesheet;
        }

        $defaultStylesheet = dirname($templateFile) . '/default.css';
        if (file_exists($defaultStylesheet)) {
            return $defaultStylesheet;
        }

        return '';
    }

    /**
     * Resolve template file path with fallback.
     */
    private static function resolveTemplateFile(string $template, string $scope): string
    {
        $templateDirs = self::getTemplateDirs($scope);
        $templateSlug = sanitize_file_name($template);
        if ($templateSlug === '') {
            $templateSlug = 'default';
        }

        foreach ($templateDirs as $templateDir) {
            $candidateFile = $templateDir . '/' . $templateSlug . '.php';
            if (file_exists($candidateFile)) {
                return $candidateFile;
            }
        }

        foreach ($templateDirs as $templateDir) {
            $defaultFile = $templateDir . '/default.php';
            if (file_exists($defaultFile)) {
                return $defaultFile;
            }
        }

        return reset($templateDirs) . '/default.php';
    }

    /**
     * Resolve ordered template directories for a scope.
     *
     * @return array<int, string>
     */
    private static function getTemplateDirs(string $scope): array
    {
        $scope = sanitize_key($scope);
        if ($scope === 'packing_slips') {
            $scope = self::SCOPE_PACKING_SLIPS;
        }

        $baseDir = self::TEMPLATE_DIRS[$scope] ?? self::TEMPLATE_DIRS[self::SCOPE_INVOICE];
        if ($scope === self::SCOPE_INVOICE) {
            return [$baseDir, self::LEGACY_INVOICE_TEMPLATE_DIR];
        }

        return [$baseDir];
    }
}
