<?php
/**
 * Site Menu renderer.
 *
 * Resolves the correct published menu for the current site root, builds its
 * tree and renders the semantic Twig template. Target of the `load_site_menu`
 * hook. Ported from the legacy SiteMenu::renderMenu()/getMenu().
 *
 * @package Mtc\Modules\SiteMenu
 */

namespace Mtc\Modules\SiteMenu\Services;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Mtc\Modules\SiteMenu\Models\SiteMenuItem;

class SiteMenuRenderer
{
    /**
     * The Twig template used to render a menu. Lives in the site theme so it is
     * themeable and wins template resolution.
     */
    protected const TEMPLATE = 'SiteMenu/site_menu.twig';

    /**
     * Render a named menu for site usage, with comprehensive caching.
     *
     * Echoes the rendered HTML (the `load_site_menu` hook is used inline in
     * Twig via hooks_do_action) and returns whether anything was rendered.
     *
     * @param string $menu name of the menu to render
     * @param array $options styling options passed through to the template
     * @return bool|null
     */
    public static function renderMenu(string $menu, array $options = []): ?bool
    {
        global $p;

        // Build cache key based on menu name and context.
        $variant = '';
        $hidePharmacyItems = !empty($p->pagedata['Hide Pharmacy Items'][0]['value'])
            || (app('twig')->getGlobals()['hide_pharmacy_items'] ?? false);

        if ($hidePharmacyItems) {
            $variant = '_without_children';
        }

        $cacheKey = SiteMenuItem::getCacheKey($menu . ':render', $variant);
        $ttl = now()->addHours(config('site_menu.cache_ttl_hours', 6));

        $html = Cache::remember($cacheKey, $ttl, function () use ($menu, $options, $variant) {
            $display_root_menu = SiteMenuItem::find(CMS_ROOT_PAGE_ID);
            if (!$display_root_menu) {
                return '';
            }

            $current_menu = null;

            // A menu name can exist under multiple roots; pick the one whose
            // top ancestor matches the current site's CMS root page.
            $candidate_menus = SiteMenuItem::where('name', $menu)
                ->where('published', 1)
                ->get();

            foreach ($candidate_menus as $candidate_menu) {
                $candidate_root_menu = $candidate_menu->getAncestors()->last();
                if ($candidate_root_menu && $candidate_root_menu->id == $display_root_menu->id) {
                    $current_menu = $candidate_menu;
                    break;
                }
            }

            if (!$current_menu || !$current_menu->published) {
                return '';
            }

            // Prepare options.
            $opts = $options;
            $opts['container_class'] = $current_menu->css_class;
            if (!isset($opts['first_container_class'])) {
                $opts['first_container_class'] = config('site_menu.first_container_class');
            }
            $opts['menu_name'] = $menu;

            // Build the tree (published only) and render it.
            $menu_tree = SiteMenuItem::fetchTree($current_menu);

            if (!count($menu_tree)) {
                return '';
            }

            return self::getMenu($menu . $variant, $menu_tree, $opts);
        });

        echo $html;
        return $html !== '' ? true : false;
    }

    /**
     * Render the menu tree to HTML via the semantic Twig template.
     *
     * @param string $name cache-context name (unused by the template, kept for parity)
     * @param Collection $menu the built menu tree
     * @param array $options styling options
     * @return string
     */
    private static function getMenu(string $name, Collection $menu, array $options): string
    {
        return App::make('twig')->render(self::TEMPLATE, [
            'items'   => $menu,
            'options' => $options,
        ]);
    }
}
