<?php

if (!defined('ABSPATH')) {
    die('You are not allowed to call this page directly.');
}

class MeprView
{
    /**
     * Get the file for a given slug.
     *
     * @param string $slug  The slug of the file.
     * @param array  $paths The paths to search for the file.
     *
     * @return string The path to the file.
     */
    public static function file($slug, $paths = [])
    {
        $paths = (empty($paths) ? self::paths() : $paths);
        $find  = $slug . '.php';

        if (!preg_match('#^/#', $find)) {
            $find = '/' . $find;
        }

        // Since we're including our default path, the file will be
        // found so we're not doing any validation for that here.
        foreach ($paths as $path) {
            if (file_exists($path . $find)) {
                return $path . $find;
            }
        }

        return false;
    }

    /**
     * Used to get a string of a view. We can use this when calling a file to
     * pass all the locally defined variables as the args variable:
     *
     * MeprView::get_string('mycoolstuff/what', get_defined_vars());
     *
     * @param string $slug  The slug of the view.
     * @param array  $vars  The variables to pass to the view.
     * @param array  $paths The paths to search for the view.
     *
     * @return string|void
     */
    public static function get_string($slug, $vars = [], $paths = [])
    {
        $paths = MeprHooks::apply_filters('mepr_view_paths_get_string_' . $slug, $paths, $slug, $vars);
        $paths = MeprHooks::apply_filters('mepr_view_paths_get_string', $paths, $slug, $vars);

        $template_part_slug = 'memberpress/' . dirname($slug);
        $template_part_name = basename($slug);

        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHookname
        do_action("get_template_part_{$template_part_slug}", $template_part_slug, $template_part_name); // Bypass MeprHooks for this one.

        $file = self::file($slug, $paths);

        if (!$file) {
            return;
        }

        // Render inside a closure that declares no parameters and creates no
        // locals: func_get_arg() reads the file path and vars without binding
        // any names, so the view scope contains exactly the caller's variables
        // and no name is reserved for internal use.
        ob_start();
        (static function () {
            extract(func_get_arg(1), EXTR_SKIP);
            require func_get_arg(0);
        })($file, $vars);
        $view = ob_get_clean();

        $view = MeprHooks::apply_filters('mepr_view_get_string_' . $slug, $view, $vars); // Slug specific filter.
        $view = MeprHooks::apply_filters('mepr_view_get_string', $view, $slug, $vars); // General filter.

        return $view;
    }

    /**
     * Used to render a view. We can use this when calling a file to
     * pass all the locally defined variables as the args variable:
     *
     * MeprView::render('mycoolstuff/what', get_defined_vars());
     *
     * @param string $slug  The slug of the view.
     * @param array  $vars  The variables to pass to the view.
     * @param array  $paths The paths to search for the view.
     *
     * @return string The string of the view.
     */
    public static function render($slug, $vars = [], $paths = [])
    {
        $view = self::get_string($slug, $vars, $paths);

        echo $view; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

        return $view;
    }

    /**
     * Get the paths for the views.
     *
     * @return array The paths for the views.
     */
    public static function paths()
    {
        $paths = [];

        $template_path   = get_template_directory();
        $stylesheet_path = get_stylesheet_directory();

        // Put child theme's first if one's being used.
        if ($stylesheet_path !== $template_path) {
            $paths[] = "{$stylesheet_path}/memberpress";
        }

        $paths[] = "{$template_path}/memberpress";
        $paths[] = MEPR_BRAND_VIEWS_PATH;
        $paths[] = MEPR_VIEWS_PATH;

        return MeprHooks::apply_filters('mepr_view_paths', $paths);
    }
}
