<?php

namespace GriffinForms\Includes\Packages;

use GriffinForms\Traits\Singleton;

class PackageBootstrap extends \GriffinForms\Format
{
    use Singleton;

    protected $registry;
    protected $resolver;
    protected $store;

    protected function setRegistry()
    {
        $this->registry = PackageRegistry::getInstance();
    }

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

    protected function setStore()
    {
        $this->store = PackageStateStore::getInstance();
    }

    public function registerHooks(): void
    {
        add_action('plugins_loaded', [$this, 'refreshCurrentState'], 1);
        add_action('activated_plugin', [$this, 'handleActivatedPlugin'], 10, 2);
        add_action('deactivated_plugin', [$this, 'handleDeactivatedPlugin'], 10, 2);
        add_action('deleted_plugin', [$this, 'handleDeletedPlugin'], 10, 2);
        add_action('upgrader_process_complete', [$this, 'handleUpgraderProcessComplete'], 10, 2);
    }

    public function refreshCurrentState(): void
    {
        $previous = $this->store->getSnapshot();
        $current = $this->resolver->refreshState();

        foreach (($current['packages'] ?? []) as $package_id => $package_state) {
            if (!empty($package_state['is_present'])) {
                $this->store->markFirstInstalled($package_id, get_current_user_id());
            }
        }

        $this->logStateTransitions($previous, $current);
    }

    public function handleActivatedPlugin(string $plugin, bool $network_wide = false): void
    {
        $package = $this->registry->getByBootstrapFile($plugin);
        if (!$package) {
            return;
        }

        $package_id = (string) ($package['package_id'] ?? '');
        if ($package_id === '') {
            return;
        }

        $this->store->markActivated($package_id, get_current_user_id());
        $this->refreshCurrentState();
    }

    public function handleDeactivatedPlugin(string $plugin, bool $network_wide = false): void
    {
        $package = $this->registry->getByBootstrapFile($plugin);
        if (!$package) {
            return;
        }

        $package_id = (string) ($package['package_id'] ?? '');
        if ($package_id === '') {
            return;
        }

        $this->store->markDeactivated($package_id, get_current_user_id());
        $this->refreshCurrentState();
    }

    public function handleDeletedPlugin(string $plugin, bool $deleted = false): void
    {
        $package = $this->registry->getByBootstrapFile($plugin);
        if (!$package) {
            return;
        }

        $package_id = (string) ($package['package_id'] ?? '');
        if ($package_id === '') {
            return;
        }

        $this->store->markDeleted($package_id, get_current_user_id());
        $this->refreshCurrentState();
    }

    public function handleUpgraderProcessComplete($upgrader, array $hook_extra = []): void
    {
        $this->refreshCurrentState();
    }

    protected function logStateTransitions(array $previous, array $current): void
    {
        $previous_packages = is_array($previous['packages'] ?? null) ? $previous['packages'] : [];
        $current_packages = is_array($current['packages'] ?? null) ? $current['packages'] : [];

        if (empty($previous_packages)) {
            return;
        }

        foreach ($current_packages as $package_id => $package_state) {
            $previous_state = is_array($previous_packages[$package_id] ?? null) ? $previous_packages[$package_id] : [];
            $item_type = 'package';
            $item_id = 0;
            $user_id = get_current_user_id();

            if (($previous_state['is_present'] ?? null) !== ($package_state['is_present'] ?? null)) {
                $this->log->add(
                    'info',
                    $item_type,
                    $item_id,
                    $user_id,
                    sprintf(
                        'Package [%s] presence changed to %s.',
                        $package_id,
                        !empty($package_state['is_present']) ? 'present' : 'absent'
                    ),
                    'package_lifecycle'
                );
            }

            if (($previous_state['is_active'] ?? null) !== ($package_state['is_active'] ?? null)) {
                $this->log->add(
                    'info',
                    $item_type,
                    $item_id,
                    $user_id,
                    sprintf(
                        'Package [%s] activation state changed to %s.',
                        $package_id,
                        !empty($package_state['is_active']) ? 'active' : 'inactive'
                    ),
                    'package_lifecycle'
                );
            }

            if (($previous_state['compatibility_state'] ?? null) !== ($package_state['compatibility_state'] ?? null)) {
                $log_type = $package_state['compatibility_state'] === 'compatible' ? 'info' : 'warning';
                $this->log->add(
                    $log_type,
                    $item_type,
                    $item_id,
                    $user_id,
                    sprintf(
                        'Package [%s] compatibility state changed to %s.',
                        $package_id,
                        (string) ($package_state['compatibility_state'] ?? 'unknown')
                    ),
                    'package_compatibility'
                );
            }

            if (($previous_state['entitlement_state'] ?? null) !== ($package_state['entitlement_state'] ?? null)) {
                $log_type = $package_state['entitlement_state'] === 'verified_active' ? 'success' : 'info';
                if (in_array($package_state['entitlement_state'], ['key_not_entered', 'verified_inactive_or_expired', 'unverified_connection_issue', 'grace_period'], true)) {
                    $log_type = 'warning';
                }

                $this->log->add(
                    $log_type,
                    'license',
                    $item_id,
                    $user_id,
                    sprintf(
                        'Package [%s] entitlement state changed to %s.',
                        $package_id,
                        (string) ($package_state['entitlement_state'] ?? 'not_applicable')
                    ),
                    'license_state'
                );
            }
        }
    }
}
