<?php

/**
 * Menu Registry
 *
 * Central registry service for declaring all WordPress admin menu and submenu items.
 * Supports dynamic condition checks for visibility and linking to appropriate page shells.
 *
 * @package ProRank\Core
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * MenuRegistry class
 *
 * Manages registration of admin menu items with conditional visibility
 */


class MenuRegistry {
    
    /**
     * Top-level menu definitions
     *
     * @var array<string, array>
     */
    private array $top_level_menus = [];
    
    /**
     * Submenu definitions
     *
     * @var array<string, array>
     */
    private array $sub_menus = [];
    
    /**
     * Register a top-level menu item
     *
     * @param string        $slug               Unique slug for the menu page
     * @param string        $page_title         Title displayed in browser title bar
     * @param string        $menu_title         Title displayed in admin menu
     * @param string        $capability         WordPress capability required
     * @param callable      $render_callback    Function to render page content
     * @param string        $icon_svg_or_css_var Icon URL, SVG, or CSS variable
     * @param callable|null $condition_callback Optional visibility condition check
     * @param int|null      $position           Optional menu position
     * @return void
     */
    public function register_top_level(
        string $slug,
        string $page_title,
        string $menu_title,
        string $capability,
        callable $render_callback,
        string $icon_svg_or_css_var = '',
        ?callable $condition_callback = null,
        ?int $position = null
    ): void {
        $this->top_level_menus[$slug] = [
            'slug' => $slug,
            'page_title' => $page_title,
            'menu_title' => $menu_title,
            'capability' => $capability,
            'render_callback' => $render_callback,
            'icon' => $icon_svg_or_css_var,
            'condition_callback' => $condition_callback,
            'position' => $position,
        ];
    }
    
    /**
     * Register a submenu item
     *
     * @param string        $parent_slug        Parent menu slug
     * @param string        $slug               Unique slug for the submenu page
     * @param string        $page_title         Title displayed in browser title bar
     * @param string        $menu_title         Title displayed in admin menu
     * @param string        $capability         WordPress capability required
     * @param callable      $render_callback    Function to render page content
     * @param callable|null $condition_callback Optional visibility condition check
     * @param int|null      $position           Optional menu position
     * @return void
     */
    public function register_sub_menu(
        string $parent_slug,
        string $slug,
        string $page_title,
        string $menu_title,
        string $capability,
        callable $render_callback,
        ?callable $condition_callback = null,
        ?int $position = null
    ): void {
        if (!isset($this->sub_menus[$parent_slug])) {
            $this->sub_menus[$parent_slug] = [];
        }
        
        $this->sub_menus[$parent_slug][$slug] = [
            'parent_slug' => $parent_slug,
            'slug' => $slug,
            'page_title' => $page_title,
            'menu_title' => $menu_title,
            'capability' => $capability,
            'render_callback' => $render_callback,
            'condition_callback' => $condition_callback,
            'position' => $position,
        ];
    }
    
    /**
     * Get all registered menu data
     *
     * Returns raw definitions without condition filtering.
     * Useful for features like Command Palette.
     *
     * @return array{top_level: array, sub_menus: array}
     */
    public function get_registered_menus_data(): array {
        return [
            'top_level' => $this->top_level_menus,
            'sub_menus' => $this->sub_menus,
        ];
    }
    
    /**
     * Register menus with WordPress
     *
     * Should be hooked to 'admin_menu' action.
     * Executes condition callbacks and registers menus accordingly.
     *
     * @return void
     */
    public function register_menus(): void {
        // Register top-level menus
        foreach ($this->top_level_menus as $menu) {
            // Skip items whose condition check fails (e.g. module disabled)
            if (is_callable($menu['condition_callback']) && !call_user_func($menu['condition_callback'])) {
                continue;
            }

            // Register the menu page using already-translated titles.
            $hook_suffix = add_menu_page(
                $menu['page_title'],
                $menu['menu_title'],
                $menu['capability'],
                $menu['slug'],
                $menu['render_callback'],
                $menu['icon'],
                $menu['position']
            );
            
            // Hook suffix will be false if registration failed
        }
        
        // Register submenus
        foreach ($this->sub_menus as $parent_slug => $submenus) {
            // Check if parent exists (either in our registry or WordPress core)
            if (!$this->parent_menu_exists($parent_slug)) {
                continue;
            }
            
            // Sort submenus by position if specified
            uasort($submenus, function ($a, $b) {
                $pos_a = $a['position'] ?? 99;
                $pos_b = $b['position'] ?? 99;
                return $pos_a <=> $pos_b;
            });
            
            foreach ($submenus as $submenu) {
                // Skip items whose condition check fails
                if (is_callable($submenu['condition_callback']) && !call_user_func($submenu['condition_callback'])) {
                    continue;
                }

                // Register the submenu page using already-translated titles.
                $hook_suffix = add_submenu_page(
                    $submenu['parent_slug'],
                    $submenu['page_title'],
                    $submenu['menu_title'],
                    $submenu['capability'],
                    $submenu['slug'],
                    $submenu['render_callback'],
                    $submenu['position']
                );
                
                if ($hook_suffix === false) {
                    prorank_log(sprintf(
                        'ProRank SEO: Failed to register submenu "%s" under parent "%s"',
                        $submenu['slug'],
                        $submenu['parent_slug']
                    ));
                }
            }
        }
        
        // Fix submenu order to ensure Dashboard is first and remove duplicate
        add_filter('submenu_file', [$this, 'fix_submenu_order'], 999);
    }
    
    /**
     * Fix submenu order and remove duplicate ProRank SEO item
     *
     * @param string $submenu_file Current submenu file
     * @return string
     */
    public function fix_submenu_order($submenu_file) {
        global $submenu;
        
        // Only process our menu
        if (!isset($submenu['prorank-seo'])) {
            return $submenu_file;
        }
        
        // Remove this filter after first run to avoid multiple executions
        remove_filter('submenu_file', [$this, 'fix_submenu_order'], 999);
        
        // WordPress automatically adds a submenu with same slug as parent
        // We want to keep only our custom Dashboard entry
        $new_submenu = [];
        $dashboard_item = null;
        
        foreach ($submenu['prorank-seo'] as $item) {
            // Skip the auto-generated "ProRank SEO" item that's not Dashboard
            if ($item[2] === 'prorank-seo' && $item[0] === 'Dashboard') {
                $dashboard_item = $item;
            } elseif ($item[2] !== 'prorank-seo') {
                $new_submenu[] = $item;
            }
        }
        
        // Put Dashboard at the beginning
        if ($dashboard_item) {
            array_unshift($new_submenu, $dashboard_item);
        }
        
        // Update the global submenu
        $submenu['prorank-seo'] = array_values($new_submenu);
        
        return $submenu_file;
    }
    
    /**
     * Check if a parent menu exists
     *
     * @param string $parent_slug Parent menu slug to check
     * @return bool
     */
    private function parent_menu_exists(string $parent_slug): bool {
        // Check if it's one of our registered top-level menus
        if (isset($this->top_level_menus[$parent_slug])) {
            // Check if it passed its condition check
            $menu = $this->top_level_menus[$parent_slug];
            if (is_callable($menu['condition_callback'])) {
                return call_user_func($menu['condition_callback']);
            }
            return true;
        }
        
        // Check if it's a WordPress core menu
        global $menu;
        if (!is_array($menu)) {
            return false;
        }
        
        foreach ($menu as $menu_item) {
            if (isset($menu_item[2]) && $menu_item[2] === $parent_slug) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Remove a registered menu
     *
     * @param string $slug Menu slug to remove
     * @return bool Success
     */
    public function remove_menu(string $slug): bool {
        if (isset($this->top_level_menus[$slug])) {
            unset($this->top_level_menus[$slug]);
            // Also remove any submenus under this parent
            unset($this->sub_menus[$slug]);
            return true;
        }
        
        // Check if it's a submenu
        foreach ($this->sub_menus as $parent_slug => &$submenus) {
            if (isset($submenus[$slug])) {
                unset($submenus[$slug]);
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Update menu properties
     *
     * @param string $slug       Menu slug to update
     * @param array  $properties Properties to update
     * @return bool Success
     */
    public function update_menu(string $slug, array $properties): bool {
        if (isset($this->top_level_menus[$slug])) {
            $this->top_level_menus[$slug] = array_merge(
                $this->top_level_menus[$slug],
                $properties
            );
            return true;
        }
        
        // Check submenus
        foreach ($this->sub_menus as &$submenus) {
            if (isset($submenus[$slug])) {
                $submenus[$slug] = array_merge(
                    $submenus[$slug],
                    $properties
                );
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Get menu by slug
     *
     * @param string $slug Menu slug
     * @return array|null Menu data or null if not found
     */
    public function get_menu(string $slug): ?array {
        if (isset($this->top_level_menus[$slug])) {
            return $this->top_level_menus[$slug];
        }
        
        foreach ($this->sub_menus as $submenus) {
            if (isset($submenus[$slug])) {
                return $submenus[$slug];
            }
        }
        
        return null;
    }
    
    /**
     * Check if menu is registered
     *
     * @param string $slug Menu slug
     * @return bool
     */
    public function has_menu(string $slug): bool {
        return $this->get_menu($slug) !== null;
    }
}
