<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Admin\Lifecycle;

use BookiFlex\Core\Contract\PluginInterface;
use BookiFlex\Core\Contract\UninstallerInterface;
use Psr\Log\LoggerInterface;

defined( 'ABSPATH' ) || exit;

/**
 * Abstract Uninstaller - orchestrator for plugin uninstallation
 *
 * This class coordinates the uninstallation process, delegating actual
 * data cleanup to concrete implementations (Free/Pro Uninstallers) and
 * extensions that implement UninstallerInterface.
 */
abstract class AbstractUninstaller
{
    /**
     * Logger instance for uninstall operations
     * Set via setLogger() before uninstall if available
     */
    protected static ?LoggerInterface $logger = null;

    final public function __construct()
    {
    }

    /**
     * Set logger for uninstall operations
     */
    public static function setLogger(?LoggerInterface $logger): void
    {
        self::$logger = $logger;
    }

    /**
     * Register uninstall hook
     *
     * @param PluginInterface $plugin Plugin instance
     */
    public static function register(PluginInterface $plugin): void
    {
        register_uninstall_hook(
            $plugin->getContainer()->get('plugin_file'),
            [static::class, 'uninstallStatic']
        );
    }

    /**
     * Static entry point for WordPress uninstall hook
     *
     * Creates an instance and delegates to instance method.
     * WordPress requires static method for uninstall hook.
     */
    public static function uninstallStatic(): void
    {
        $uninstaller = new static();
        $uninstaller->uninstall();
    }

    /**
     * Main uninstall orchestrator
     *
     * Coordinates the uninstallation process:
     * 1. Always delete version-specific data
     * 2. Delete shared data only if other edition is not installed
     */
    public function uninstall(): void
    {
        if (!current_user_can('activate_plugins')) {
            return;
        }

        try {
            // ALWAYS delete version-specific data
            $this->deleteVersionData();

            // Delete shared data ONLY if other edition is not installed
	        $this->deleteSharedData();

            // Clear WordPress cache
            wp_cache_flush();

        } catch (\Throwable $e) {
            self::$logger?->error('BookiFlex uninstall error', ['error' => $e->getMessage()]);
        }
    }

    /**
     * Call method on all extension uninstallers
     *
     * Iterates through extension uninstallers and calls the specified method.
     * Only calls methods on objects implementing UninstallerInterface.
     *
     * @param string $method Method name to call (deleteVersionData or deleteSharedData)
     */
    protected function callExtensionUninstallers(string $method): void
    {
        $uninstallers = $this->getExtensionUninstallers();

        foreach ($uninstallers as $uninstaller) {
            if ($uninstaller instanceof UninstallerInterface) {
                $uninstaller->$method();
            }
        }
    }

    /**
     * Instantiate uninstallers from class configurations
     *
     * Creates instances of extension uninstallers from array of configurations.
     * Each configuration is [className, constructorArgs].
     * Uses class_exists() to gracefully handle missing extensions.
     *
     * @param array $uninstallerClasses Array of [class, args] configurations
     * @return array Array of uninstaller instances
     */
    protected function instantiateUninstallers(array $uninstallerClasses): array
    {
        $instances = [];

        foreach ($uninstallerClasses as $classConfig) {
            $class = $classConfig[0];
            $args = $classConfig[1] ?? [];

            if (class_exists($class)) {
                $instances[] = new $class(...$args);
            }
        }

        return $instances;
    }

    /**
     * Delete version-specific data
     *
     * This method is ALWAYS called during uninstall.
     * Implement this to delete:
     * - Edition-specific options (bookiflex_free_*, bookiflex_pro_*)
     * - Edition-specific transients
     * - Edition-specific pages/posts
     * - Any other data unique to this edition
     *
     * Also calls extension uninstallers' deleteVersionData() methods.
     */
    abstract protected function deleteVersionData(): void;

    /**
     * Delete shared data
     *
     * This method is called ONLY when other edition is NOT installed.
     * Implement this to delete:
     * - Core database tables
     * - Shared options (bookiflex_*, Carbon Fields)
     * - WordPress roles and capabilities
     * - Custom post types
     * - Any data common to both Free and Pro
     *
     * Also calls extension uninstallers' deleteSharedData() methods.
     */
    abstract protected function deleteSharedData(): void;

    /**
     * Get extension uninstallers
     *
     * Returns array of extension uninstaller instances.
     * Extensions must implement UninstallerInterface.
     *
     * @return array Array of UninstallerInterface instances
     */
    abstract protected function getExtensionUninstallers(): array;
}
