<?php

declare(strict_types=1);

namespace FleekDash\Admin\Menu;

/**
 * Native Submenu Fallback
 *
 * Provides baseline WordPress core submenu rows (in raw $submenu shape) for native parents
 * whose children were lost because:
 *   - `wp-admin/menu.php` was previously loaded via `require_once` (cannot re-execute), and
 *   - `admin_menu` already fired in the same request (did_action guard prevents re-firing).
 *
 * The resulting rows mirror WordPress core's wp-admin/menu.php assignments for the relevant
 * parents and are plugged through {@see MenuItemFormatter::attachSubmenuRowsToTopLevel()} so
 * capability checks, translations and routing behave exactly like normal WP submenus.
 *
 * @package FleekDash\Admin\Menu
 */
final class NativeSubmenuFallback
{
    private const LABEL_ADD_NEW = 'Add New';
    private const POST_TYPE_PARENT_PREFIX = 'edit.php?post_type=';

    /**
     * Hardcoded baseline for non–post-type native parents. Shape matches WordPress global
     * `$submenu[$parent]` rows: [0=>title, 1=>capability, 2=>slug].
     *
     * NB: Keys are preserved as WordPress core positions (5, 10, …) so sorting downstream
     * produces the same order users see in wp-admin.
     */
    private const STATIC_NATIVE_ROWS = [
        'edit.php' => [
            5 => ['All Posts', 'edit_posts', 'edit.php'],
            10 => [self::LABEL_ADD_NEW, 'edit_posts', 'post-new.php'],
            15 => ['Categories', 'manage_categories', 'edit-tags.php?taxonomy=category'],
            16 => ['Tags', 'manage_categories', 'edit-tags.php?taxonomy=post_tag'],
        ],
        self::POST_TYPE_PARENT_PREFIX . 'page' => [
            5 => ['All Pages', 'edit_pages', self::POST_TYPE_PARENT_PREFIX . 'page'],
            10 => [self::LABEL_ADD_NEW, 'edit_pages', 'post-new.php?post_type=page'],
        ],
        'upload.php' => [
            5 => ['Library', 'upload_files', 'upload.php'],
            10 => ['Add New Media File', 'upload_files', 'media-new.php'],
        ],
        'themes.php' => [
            5 => ['Themes', 'switch_themes', 'themes.php'],
            6 => ['Customize', 'customize', 'customize.php'],
        ],
        'plugins.php' => [
            5 => ['Installed Plugins', 'activate_plugins', 'plugins.php'],
            10 => ['Add New Plugin', 'install_plugins', 'plugin-install.php'],
            15 => ['Plugin File Editor', 'edit_plugins', 'plugin-editor.php'],
        ],
        'users.php' => [
            5 => ['All Users', 'list_users', 'users.php'],
            10 => ['Add New User', 'create_users', 'user-new.php'],
            15 => ['Profile', 'read', 'profile.php'],
        ],
        'tools.php' => [
            5 => ['Available Tools', 'edit_posts', 'tools.php'],
            10 => ['Import', 'import', 'import.php'],
            15 => ['Export', 'export', 'export.php'],
            20 => ['Site Health', 'view_site_health_checks', 'site-health.php'],
            25 => ['Export Personal Data', 'export_others_personal_data', 'export-personal-data.php'],
            30 => ['Erase Personal Data', 'erase_others_personal_data', 'erase-personal-data.php'],
        ],
        'options-general.php' => [
            10 => ['General', 'manage_options', 'options-general.php'],
            15 => ['Writing', 'manage_options', 'options-writing.php'],
            20 => ['Reading', 'manage_options', 'options-reading.php'],
            25 => ['Discussion', 'manage_options', 'options-discussion.php'],
            30 => ['Media', 'manage_options', 'options-media.php'],
            35 => ['Permalinks', 'manage_options', 'options-permalink.php'],
            40 => ['Privacy', 'manage_privacy_options', 'options-privacy.php'],
        ],
    ];

    /**
     * Return WP-core baseline submenu rows for the given native parent slug, translated with the
     * `default` textdomain so they match the user's admin locale.
     *
     * Returns `[]` when the slug is not a known native parent OR (for post-type parents) the post
     * type object is not registered / not UI-visible.
     *
     * @return array<int, array{0:string,1:string,2:string}>
     */
    public static function getBaselineRows(string $parentSlug): array
    {
        $rows = [];
        if ($parentSlug === '') {
            return $rows;
        }
        if (isset(self::STATIC_NATIVE_ROWS[$parentSlug])) {
            $rows = self::translateStaticRows(self::STATIC_NATIVE_ROWS[$parentSlug]);
        } elseif (\str_starts_with($parentSlug, self::POST_TYPE_PARENT_PREFIX)) {
            $rows = self::rowsForPostTypeParent($parentSlug);
        }
        return $rows;
    }

    /**
     * @param array<int, array{0:string,1:string,2:string}> $rows
     * @return array<int, array{0:string,1:string,2:string}>
     */
    private static function translateStaticRows(array $rows): array
    {
        $translated = [];
        foreach ($rows as $key => $row) {
            $translated[$key] = [
                // 'default' textdomain → WordPress core's own translation catalog.
                \translate($row[0], 'default'),
                $row[1],
                $row[2],
            ];
        }
        return $translated;
    }

    /**
     * Build submenu rows for a `edit.php?post_type=<X>` parent by reading the post type's labels
     * and capability map; mirrors `wp-admin/menu.php` behavior for registered custom post types.
     *
     * @return array<int, array{0:string,1:string,2:string}>
     */
    private static function rowsForPostTypeParent(string $parentSlug): array
    {
        $rows = [];
        $postTypeName = \substr($parentSlug, \strlen(self::POST_TYPE_PARENT_PREFIX));
        if ($postTypeName === '' || !\function_exists('get_post_type_object')) {
            return $rows;
        }

        $postType = \get_post_type_object($postTypeName);
        if (!$postType instanceof \WP_Post_Type) {
            return $rows;
        }

        $editCap = self::readPostTypeCap($postType, 'edit_posts');
        $createCap = self::readPostTypeCap($postType, 'create_posts');
        $allLabel = self::readPostTypeLabel($postType, 'all_items', 'All Items');
        $addNewLabel = self::readPostTypeLabel($postType, 'add_new', self::LABEL_ADD_NEW);

        $rows = [
            5 => [$allLabel, $editCap, self::POST_TYPE_PARENT_PREFIX . $postTypeName],
            10 => [$addNewLabel, $createCap, 'post-new.php?post_type=' . $postTypeName],
        ];

        foreach (self::resolvePostTypeTaxonomySubmenus($postType, $postTypeName) as $index => $row) {
            $rows[15 + $index] = $row;
        }

        return $rows;
    }

    /**
     * @return array<int, array{0:string,1:string,2:string}>
     */
    private static function resolvePostTypeTaxonomySubmenus(\WP_Post_Type $postType, string $postTypeName): array
    {
        if (!\function_exists('get_object_taxonomies') || !\function_exists('get_taxonomy')) {
            return [];
        }

        $taxonomies = \get_object_taxonomies($postTypeName, 'objects');
        if (!\is_array($taxonomies) || $taxonomies === []) {
            return [];
        }

        unset($postType); // reserved for future per-post-type filtering rules
        $rows = [];
        foreach ($taxonomies as $taxonomyName => $taxonomyObject) {
            if (!\is_string($taxonomyName) || !\is_object($taxonomyObject)) {
                continue;
            }
            $showUi = $taxonomyObject->show_ui ?? true;
            $showInMenu = $taxonomyObject->show_in_menu ?? $showUi;
            if (!$showUi || !$showInMenu) {
                continue;
            }
            $label = self::readTaxonomyLabel($taxonomyObject, $taxonomyName);
            $cap = self::readTaxonomyManageCap($taxonomyObject);
            $rows[] = [
                $label,
                $cap,
                'edit-tags.php?taxonomy=' . $taxonomyName . '&post_type=' . $postTypeName,
            ];
        }
        return $rows;
    }

    private static function readPostTypeCap(\WP_Post_Type $postType, string $capKey): string
    {
        if (isset($postType->cap->{$capKey}) && \is_string($postType->cap->{$capKey})) {
            return $postType->cap->{$capKey};
        }
        return 'edit_posts';
    }

    private static function readPostTypeLabel(\WP_Post_Type $postType, string $labelKey, string $fallback): string
    {
        if (
            isset($postType->labels->{$labelKey}) &&
            \is_string($postType->labels->{$labelKey}) &&
            $postType->labels->{$labelKey} !== ''
        ) {
            return $postType->labels->{$labelKey};
        }
        return \translate($fallback, 'default');
    }

    private static function readTaxonomyLabel(object $taxonomyObject, string $taxonomyName): string
    {
        if (
            isset($taxonomyObject->labels->menu_name) &&
            \is_string($taxonomyObject->labels->menu_name) &&
            $taxonomyObject->labels->menu_name !== ''
        ) {
            return $taxonomyObject->labels->menu_name;
        }
        if (
            isset($taxonomyObject->labels->name) &&
            \is_string($taxonomyObject->labels->name) &&
            $taxonomyObject->labels->name !== ''
        ) {
            return $taxonomyObject->labels->name;
        }
        return \ucfirst($taxonomyName);
    }

    private static function readTaxonomyManageCap(object $taxonomyObject): string
    {
        if (
            isset($taxonomyObject->cap->manage_terms) &&
            \is_string($taxonomyObject->cap->manage_terms)
        ) {
            return $taxonomyObject->cap->manage_terms;
        }
        return 'manage_categories';
    }
}
