<?php

namespace GriffinForms\Includes\Addons;

use GriffinForms\Traits\Singleton;

/**
 * Central registry for GriffinForms addons.
 *
 * Tracks addon installation state, versions, icons, and metadata.
 * Providers and integrations can query this registry instead of running
 * repeated plugin/class checks.
 */
class Registry
{
    use Singleton;

    /**
     * Cached addon metadata keyed by slug.
     *
     * @var array<string,array>
     */
    private $addons = [];

    /**
     * Map of provider IDs to addon slugs.
     *
     * @var array<string,string>
     */
    private $provider_map = [];

    private function __construct()
    {
        $this->loadAddons();
    }

    /**
     * Refresh the registry data.
     */
    public function refresh(): void
    {
        $this->loadAddons();
    }

    /**
     * Get metadata for all registered addons.
     *
     * @return array
     */
    public function getAll(): array
    {
        return $this->addons;
    }

    /**
     * Get addon metadata by slug.
     *
     * @param string $slug
     * @return array|null
     */
    public function get(string $slug): ?array
    {
        $slug = sanitize_key($slug);
        return $this->addons[$slug] ?? null;
    }

    /**
     * Return addon metadata associated with a provider.
     *
     * @param string $provider_id
     * @return array|null
     */
    public function getByProvider(string $provider_id): ?array
    {
        $slug = $this->provider_map[$provider_id] ?? null;
        if (!$slug) {
            return null;
        }

        return $this->get($slug);
    }

    /**
     * Determine whether the addon is installed.
     *
     * @param string $slug
     * @return bool
     */
    public function isInstalled(string $slug): bool
    {
        $addon = $this->get($slug);
        if (!$addon) {
            return false;
        }

        return (bool) ($addon['is_installed'] ?? false);
    }

    /**
     * Determine whether the addon is active.
     *
     * @param string $slug
     * @return bool
     */
    public function isActive(string $slug): bool
    {
        $addon = $this->get($slug);
        if (!$addon) {
            return false;
        }

        return (bool) ($addon['is_active'] ?? false);
    }

    /**
     * Get installed version.
     *
     * @param string $slug
     * @return string|null
     */
    public function getVersion(string $slug): ?string
    {
        $addon = $this->get($slug);
        if (!$addon) {
            return null;
        }

        return $addon['version'] ?? null;
    }

    /**
     * Load addon metadata from defaults and filters.
     *
     * @return void
     */
    private function loadAddons(): void
    {
        $defaults = [];
        $registered = apply_filters('griffinforms_register_addons', $defaults);

        if (!is_array($registered)) {
            $registered = [];
        }

        $this->addons = [];
        $this->provider_map = [];

        foreach ($registered as $slug => $addon) {
            $slug = sanitize_key($slug);
            $normalized = $this->normalizeAddon($slug, $addon);
            $this->addons[$slug] = $normalized;

            $providers = $normalized['providers'] ?? [];
            foreach ((array) $providers as $provider_id) {
                $provider_id = sanitize_key($provider_id);
                if (!empty($provider_id)) {
                    $this->provider_map[$provider_id] = $slug;
                }
            }
        }
    }

    /**
     * Normalize addon metadata and detect installation state.
     *
     * @param string $slug
     * @param array $addon
     * @return array
     */
    private function normalizeAddon(string $slug, $addon): array
    {
        if (!is_array($addon)) {
            $addon = [];
        }

        $defaults = [
            'slug'         => $slug,
            'name'         => $slug,
            'type'         => 'integration',
            'category'     => 'general',
            'is_paid'      => false,
            'providers'    => [],
            'icon'         => '',
            'download_url' => '',
            'plugin_file'  => '',
            'version'      => null,
            'is_installed' => false,
            'is_active'    => false,
        ];

        $addon = array_merge($defaults, $addon);

        $plugin_file = $addon['plugin_file'];
        if (!empty($plugin_file)) {
            $plugin_file = plugin_basename($plugin_file);
            $addon = $this->detectPluginState($addon, $plugin_file);
        }

        return $addon;
    }

    /**
     * Detect plugin installation and activation status.
     *
     * @param array $addon
     * @param string $plugin_file
     * @return array
     */
    private function detectPluginState(array $addon, string $plugin_file): array
    {
        if (!function_exists('get_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }

        $plugins = get_plugins();
        if (isset($plugins[$plugin_file])) {
            $addon['is_installed'] = true;
            $addon['version'] = $plugins[$plugin_file]['Version'] ?? $addon['version'];
        }

        if (function_exists('is_plugin_active')) {
            $addon['is_active'] = is_plugin_active($plugin_file);
        } else {
            $addon['is_active'] = false;
        }

        $addon['plugin_file'] = $plugin_file;

        return $addon;
    }
}
