<?php

namespace GriffinForms\Includes\Menus;

use GriffinForms\Includes\Packages\PackageAdmission;
use GriffinForms\Traits\Singleton;

class MenuProviderRegistry extends \GriffinForms\Format
{
    use Singleton;

    protected $package_admission;
    protected $providers = [];
    protected $blocked_providers = [];

    protected function setPackageAdmission()
    {
        $this->package_admission = PackageAdmission::getInstance();
    }

    protected function setProviders()
    {
        $this->refresh();
    }

    public function refresh(): void
    {
        $registered = apply_filters('griffinforms_register_menu_providers', []);
        if (!is_array($registered)) {
            $registered = [];
        }

        $this->providers = [];
        $this->blocked_providers = [];

        foreach ($registered as $provider_id => $provider) {
            $normalized = $this->normalizeProvider((string) $provider_id, $provider);
            if (empty($normalized)) {
                continue;
            }

            $resolved_provider_id = (string) $normalized['provider_id'];
            if (empty($normalized['package_admitted'])) {
                $this->blocked_providers[$resolved_provider_id] = $normalized;
                continue;
            }

            $this->providers[$resolved_provider_id] = $normalized;
        }
    }

    public function getAll(): array
    {
        return $this->providers;
    }

    public function getBlocked(): array
    {
        return $this->blocked_providers;
    }

    public function getByVisibility(string $visibility = 'submenu'): array
    {
        $visibility = sanitize_key($visibility);

        return array_filter($this->providers, static function (array $provider) use ($visibility) {
            return (string) ($provider['visibility'] ?? 'submenu') === $visibility;
        });
    }

    protected function normalizeProvider(string $provider_id, $provider): array
    {
        if (!is_array($provider)) {
            return [];
        }

        $raw_provider = $provider;

        $provider_id = sanitize_key((string) ($provider['provider_id'] ?? $provider['id'] ?? $provider_id));
        if ($provider_id === '') {
            return [];
        }

        $page_slug = sanitize_key((string) ($provider['page_slug'] ?? ''));
        if ($page_slug === '') {
            return [];
        }

        $visibility = sanitize_key((string) ($provider['visibility'] ?? 'submenu'));
        if (!in_array($visibility, ['submenu', 'internal'], true)) {
            $visibility = 'submenu';
        }

        $capability = sanitize_key((string) ($provider['capability'] ?? 'manage_options'));
        $package_id = sanitize_key((string) ($provider['package_id'] ?? 'core'));
        if ($package_id === '') {
            $package_id = 'core';
        }

        $admission_record = $this->package_admission->normalizeProvider([
            'id' => $provider_id,
            'provider_id' => $provider_id,
            'package_id' => $package_id,
            'requires' => is_array($raw_provider['requires'] ?? null) ? $raw_provider['requires'] : [],
            'requires_entitlement' => !empty($raw_provider['requires_entitlement']),
        ], 'menu');

        $render_callback = $raw_provider['render_callback'] ?? null;
        if (!is_callable($render_callback)) {
            return [];
        }

        $parent_slug = sanitize_key((string) ($raw_provider['parent_slug'] ?? ''));
        if ($parent_slug === '') {
            $parent_slug = 'griffinforms-forms';
        }

        return [
            'id' => $provider_id,
            'provider_id' => $provider_id,
            'package_id' => $package_id,
            'page_slug' => $page_slug,
            'page_title' => (string) ($raw_provider['page_title'] ?? $page_slug),
            'menu_title' => (string) ($raw_provider['menu_title'] ?? $raw_provider['page_title'] ?? $page_slug),
            'parent_slug' => $parent_slug,
            'capability' => $capability !== '' ? $capability : 'manage_options',
            'visibility' => $visibility,
            'position' => max(0, absint($raw_provider['position'] ?? 0)),
            'render_callback' => $render_callback,
            'package_admitted' => !empty($admission_record['package_admitted']),
            'blocking_reason_key' => (string) ($admission_record['blocking_reason_key'] ?? ''),
            'requires' => $admission_record['requires'] ?? [],
        ];
    }
}
