<?php

namespace GriffinForms\Includes\Packages;

use GriffinForms\Traits\Singleton;

class PackageAdmission extends \GriffinForms\Format
{
    use Singleton;

    protected $resolver;

    protected function setResolver()
    {
        $this->resolver = PackageStateResolver::getInstance();
    }

    public function getPackageState(string $package_id): array
    {
        $state = $this->resolver->getState();
        $packages = is_array($state['packages'] ?? null) ? $state['packages'] : [];

        return is_array($packages[$package_id] ?? null) ? $packages[$package_id] : [];
    }

    public function canAdmitPackage(string $package_id, bool $require_entitlement = false): bool
    {
        $package_id = sanitize_key($package_id);
        if ($package_id === '') {
            return false;
        }

        $package_state = $this->getPackageState($package_id);
        if (empty($package_state)) {
            return false;
        }

        if (($package_state['approval_status'] ?? '') !== 'approved') {
            return false;
        }

        if ($package_id !== 'core' && empty($package_state['is_present'])) {
            return false;
        }

        if ($package_id !== 'core' && empty($package_state['is_active'])) {
            return false;
        }

        if ($package_id !== 'core' && ($package_state['compatibility_state'] ?? 'unknown') !== 'compatible') {
            return false;
        }

        if ($require_entitlement) {
            return in_array(
                (string) ($package_state['entitlement_state'] ?? ''),
                ['verified_active', 'grace_period'],
                true
            );
        }

        return true;
    }

    public function getBlockingReasonKey(string $package_id, bool $require_entitlement = false): ?string
    {
        $package_state = $this->getPackageState($package_id);
        if (empty($package_state)) {
            return 'package_unknown';
        }

        if (($package_state['approval_status'] ?? '') !== 'approved') {
            return 'package_unapproved';
        }

        if ($package_id !== 'core' && empty($package_state['is_present'])) {
            return 'package_not_installed';
        }

        if ($package_id !== 'core' && empty($package_state['is_active'])) {
            return 'package_inactive';
        }

        $compatibility_state = (string) ($package_state['compatibility_state'] ?? 'unknown');
        if ($package_id !== 'core' && $compatibility_state !== 'compatible') {
            return $compatibility_state;
        }

        if ($require_entitlement) {
            $entitlement_state = (string) ($package_state['entitlement_state'] ?? '');
            if (!in_array($entitlement_state, ['verified_active', 'grace_period'], true)) {
                return $entitlement_state !== '' ? $entitlement_state : 'entitlement_unavailable';
            }
        }

        return null;
    }

    public function normalizeProvider(array $provider, string $surface = 'integration'): array
    {
        $provider_id = sanitize_key((string) ($provider['id'] ?? $provider['provider_id'] ?? ''));
        $package_id = sanitize_key((string) ($provider['package_id'] ?? 'core'));
        $requires = $this->normalizeRequirements($provider);

        if (empty($provider['provider_id']) && $provider_id !== '') {
            $provider['provider_id'] = $package_id . '.' . $surface . '.' . $provider_id;
        }

        $provider['package_id'] = $package_id;
        $provider['surface'] = sanitize_key($surface);
        $provider['requires'] = $requires;
        $provider['requires_entitlement'] = !empty($requires['entitlements']) || !empty($provider['requires_entitlement']);
        $provider['package_admitted'] = $this->canAdmitProvider($provider);
        $provider['blocking_reason_key'] = $this->getProviderBlockingReasonKey($provider);

        return $provider;
    }

    public function canAdmitProvider(array $provider): bool
    {
        $provider = $this->normalizeProviderRecord($provider);
        if (!$this->canAdmitPackage($provider['package_id'], !empty($provider['requires']['entitlements']))) {
            return false;
        }

        if (!$this->librariesSatisfied($provider)) {
            return false;
        }

        return true;
    }

    public function getProviderBlockingReasonKey(array $provider): ?string
    {
        $provider = $this->normalizeProviderRecord($provider);
        $package_reason = $this->getBlockingReasonKey($provider['package_id'], !empty($provider['requires']['entitlements']));
        if ($package_reason !== null) {
            return $package_reason;
        }

        if (!$this->librariesSatisfied($provider)) {
            return 'library_missing';
        }

        return null;
    }

    protected function normalizeProviderRecord(array $provider): array
    {
        $package_id = sanitize_key((string) ($provider['package_id'] ?? 'core'));
        $provider['package_id'] = $package_id !== '' ? $package_id : 'core';
        $provider['requires'] = $this->normalizeRequirements($provider);

        return $provider;
    }

    protected function normalizeRequirements(array $provider): array
    {
        $raw = $provider['requires'] ?? [];
        $raw = is_array($raw) ? $raw : [];

        $entitlements = $raw['entitlements'] ?? [];
        if (!is_array($entitlements)) {
            $entitlements = [];
        }

        $libraries = $raw['libraries'] ?? [];
        if (!is_array($libraries)) {
            $libraries = [];
        }

        if (!empty($provider['requires_entitlement']) && empty($entitlements)) {
            $entitlements[] = 'package.' . sanitize_key((string) ($provider['package_id'] ?? 'core')) . '.runtime';
        }

        if (!empty($provider['requires_lib']) && empty($libraries)) {
            $libraries[] = sanitize_key((string) ($provider['id'] ?? $provider['provider_id'] ?? 'provider'));
        }

        return [
            'approval'      => array_key_exists('approval', $raw) ? !empty($raw['approval']) : true,
            'compatibility' => array_key_exists('compatibility', $raw) ? !empty($raw['compatibility']) : true,
            'capabilities'  => array_values(array_filter(array_map('sanitize_key', (array) ($raw['capabilities'] ?? [])))),
            'entitlements'  => array_values(array_filter(array_map('sanitize_key', $entitlements))),
            'libraries'     => array_values(array_filter(array_map('sanitize_key', $libraries))),
            'php'           => !empty($raw['php']) ? (string) $raw['php'] : null,
            'modules'       => array_values(array_filter(array_map('sanitize_key', (array) ($raw['modules'] ?? [])))),
            'libs'          => array_values(array_filter(array_map('sanitize_key', (array) ($raw['libs'] ?? [])))),
        ];
    }

    protected function librariesSatisfied(array $provider): bool
    {
        $libraries = (array) ($provider['requires']['libraries'] ?? []);
        if (empty($libraries)) {
            return true;
        }

        if (array_key_exists('lib_installed', $provider)) {
            return !empty($provider['lib_installed']);
        }

        return false;
    }
}
