<?php

namespace GriffinForms\Includes\Libraries;

use GriffinForms\Includes\Addons\Registry as AddonsRegistry;
use GriffinForms\Includes\Packages\PackageAdmission;
use GriffinForms\Traits\Singleton;

class LibraryRegistry extends \GriffinForms\Format
{
    use Singleton;

    protected $addons;
    protected $package_admission;
    protected $libraries = [];
    protected $provider_map = [];

    protected function setAddons()
    {
        $this->addons = AddonsRegistry::getInstance();
    }

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

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

    public function refresh(): void
    {
        $libraries = $this->buildAddonLibraries();
        $libraries = apply_filters('griffinforms_register_libraries', $libraries);
        if (!is_array($libraries)) {
            $libraries = [];
        }

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

        foreach ($libraries as $library_id => $library) {
            $normalized = $this->normalizeLibrary($library_id, $library);
            if (empty($normalized)) {
                continue;
            }

            $resolved_id = $normalized['id'];
            $this->libraries[$resolved_id] = $normalized;

            foreach ((array) ($normalized['owners'] ?? []) as $provider_id) {
                $provider_id = sanitize_key((string) $provider_id);
                if ($provider_id !== '') {
                    $this->provider_map[$provider_id] = $resolved_id;
                }
            }
        }
    }

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

    public function get(string $library_id): ?array
    {
        $library_id = sanitize_key($library_id);
        return $this->libraries[$library_id] ?? null;
    }

    public function getByProvider(string $provider_id): ?array
    {
        $provider_id = sanitize_key($provider_id);
        $library_id = $this->provider_map[$provider_id] ?? '';
        if ($library_id === '') {
            return null;
        }

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

    protected function buildAddonLibraries(): array
    {
        $libraries = [];

        foreach ($this->addons->getAll() as $slug => $addon) {
            $addon = is_array($addon) ? $addon : [];
            $providers = array_values(array_filter(array_map('sanitize_key', (array) ($addon['providers'] ?? []))));
            if (empty($providers)) {
                continue;
            }

            $library_id = sanitize_key((string) ($addon['library_id'] ?? $slug));
            if ($library_id === '') {
                continue;
            }

            $package_id = sanitize_key((string) ($addon['package_id'] ?? (!empty($addon['is_paid']) ? 'pro' : 'core')));
            if ($package_id === '') {
                $package_id = 'core';
            }

            $install_source_type = !empty($addon['plugin_file']) ? 'plugin' : 'external';
            $plugin_slug = sanitize_key((string) ($addon['slug'] ?? $slug));

            $libraries[$library_id] = [
                'id' => $library_id,
                'label' => (string) ($addon['name'] ?? $library_id),
                'package_id' => $package_id,
                'provider_id' => $package_id . '.library.' . $library_id,
                'owners' => $providers,
                'requestable_by' => array_values(array_unique(array_merge([$package_id], (array) ($addon['requestable_by'] ?? [])))),
                'install_source' => [
                    'type' => $install_source_type,
                    'slug' => $plugin_slug,
                    'plugin_file' => (string) ($addon['plugin_file'] ?? ''),
                    'download_url' => (string) ($addon['download_url'] ?? ''),
                ],
                'state' => [
                    'installed' => !empty($addon['is_installed']),
                    'active' => !empty($addon['is_active']),
                    'version' => (string) ($addon['version'] ?? ''),
                ],
            ];
        }

        return $libraries;
    }

    protected function normalizeLibrary(string $library_id, $library): array
    {
        if (!is_array($library)) {
            return [];
        }

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

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

        $owners = array_values(array_filter(array_map('sanitize_key', (array) ($library['owners'] ?? []))));
        $requestable_by = array_values(array_filter(array_map('sanitize_key', (array) ($library['requestable_by'] ?? [$package_id]))));
        if (empty($requestable_by)) {
            $requestable_by = [$package_id];
        }

        $install_source = is_array($library['install_source'] ?? null) ? $library['install_source'] : [];
        $state = is_array($library['state'] ?? null) ? $library['state'] : [];
        $provider_id = sanitize_key((string) ($library['provider_id'] ?? ($package_id . '.library.' . $library_id)));

        $installed = !empty($state['installed']);
        $active = !empty($state['active']);
        $admitted_requestors = array_values(array_filter($requestable_by, function ($requestor) {
            return $this->package_admission->canAdmitPackage((string) $requestor, false);
        }));

        return [
            'id' => $library_id,
            'label' => trim((string) ($library['label'] ?? $library_id)),
            'package_id' => $package_id,
            'provider_id' => $provider_id,
            'owners' => $owners,
            'requestable_by' => $requestable_by,
            'requestable_now' => !empty($admitted_requestors),
            'admitted_requestors' => $admitted_requestors,
            'install_source' => [
                'type' => sanitize_key((string) ($install_source['type'] ?? 'plugin')),
                'slug' => sanitize_key((string) ($install_source['slug'] ?? '')),
                'plugin_file' => (string) ($install_source['plugin_file'] ?? ''),
                'download_url' => (string) ($install_source['download_url'] ?? ''),
            ],
            'state' => [
                'installed' => $installed,
                'active' => $active,
                'version' => trim((string) ($state['version'] ?? '')),
                'action_intent' => $this->resolveActionIntent($installed, $active, !empty($admitted_requestors)),
            ],
        ];
    }

    protected function resolveActionIntent(bool $installed, bool $active, bool $requestable_now): string
    {
        if (!$requestable_now) {
            return 'unavailable';
        }

        if (!$installed) {
            return 'install';
        }

        if (!$active) {
            return 'activate';
        }

        return 'ready';
    }
}
