<?php

namespace Duplicator\Core\Upgrade;

use Duplicator\Core\Bootstrap;
use Duplicator\Utils\Logging\DupLog;

/**
 * Upgrade logic of plugin resides here
 */
class UpgradePlugin
{
    const DUP_VERSION_OPT_KEY      = 'dupli_opt_version';
    const DUP_HASH_OPT_KEY         = 'dupli_opt_hash';
    const DUP_INSTALL_INFO_OPT_KEY = 'dupli_opt_install_info';

    /**
     * Get stored plugin version with fallback filter for legacy support.
     *
     * The option value is stored as "<VERSION>|<VARIANT>" since 4.5.26. Older installs
     * may still hold a plain version string with no separator; in that case the raw
     * value is the version.
     *
     * The `duplicator_stored_version` filter lets callers provide a fallback when the
     * canonical option is absent (e.g. older option names).
     *
     * @return string|false False if the option is absent (fresh install).
     */
    public static function getStoredVersion()
    {
        $raw = get_option(self::DUP_VERSION_OPT_KEY, false);
        $raw = apply_filters('duplicator_stored_version', $raw);
        if ($raw === false) {
            return false;
        }
        $parts = explode('|', (string) $raw, 2);
        return $parts[0];
    }

    /**
     * Get the stored plugin variant identifier.
     *
     * Reads the variant from the second segment of the stored version option
     * ("<VERSION>|<VARIANT>"). When the segment is missing (older installs that
     * stored only the version), the `duplicator_undefined_default_variant` filter
     * resolves it.
     *
     * @return string Empty string when the option is absent (fresh install) and
     *                no filter provides a fallback.
     */
    public static function getStoredVariant(): string
    {
        $raw = get_option(self::DUP_VERSION_OPT_KEY, false);
        $raw = apply_filters('duplicator_stored_version', $raw);
        if ($raw === false) {
            return '';
        }
        $parts = explode('|', (string) $raw, 2);
        if (isset($parts[1]) && $parts[1] !== '') {
            return $parts[1];
        }
        return (string) apply_filters('duplicator_undefined_default_variant', '');
    }

    /**
     * Get stored addon hash
     *
     * @return string
     */
    public static function getStoredHash(): string
    {
        return (string) get_option(self::DUP_HASH_OPT_KEY, '');
    }

    /**
     * Get stored install info with fallback filter for legacy support.
     *
     * @return array{version:string,time:int,updateTime:int}|false
     */
    public static function getStoredInstallInfo()
    {
        $installInfo = get_option(self::DUP_INSTALL_INFO_OPT_KEY, false);
        return apply_filters('duplicator_stored_install_info', $installInfo);
    }

    /**
     * Check if plugin needs update (version or hash changed)
     *
     * @return bool
     */
    public static function needsUpdate(): bool
    {
        if (DUPLICATOR_VERSION != self::getStoredVersion()) {
            return true;
        }

        if (Bootstrap::getAddsHash() !== self::getStoredHash()) {
            return true;
        }

        return false;
    }

    /**
     * Perform activation action.
     *
     * @return void
     */
    public static function onActivationAction(): void
    {
        // Register upgrade hooks before performing upgrade
        UpgradeFunctions::init();

        $oldVariant = self::getStoredVariant();
        $oldVersion = self::getStoredVersion();
        $newVariant = DUPLICATOR____TYPE;
        $newVersion = DUPLICATOR_VERSION;

        // NOTE: DupLog::trace() cannot be called before updateDatabase() runs at priority 9
        // because TraceLogMng requires DynamicGlobalEntity which needs the database tables.
        // Upgrade logging is done in UpgradeFunctions::updateDatabase() after tables are created.

        do_action('duplicator_upgrade', $oldVariant, $oldVersion, $newVariant, $newVersion);

        DupLog::trace("PLUGIN UPGRADED TO VERSION: " . $newVersion);

        do_action('duplicator_after_activation', $oldVariant, $oldVersion, $newVariant, $newVersion);
    }

    /**
     * Update install info.
     *
     * @param false|string $oldVersion The last/previous installed version, is empty for new installs
     *
     * @return array{version:string,time:int,updateTime:int}
     */
    public static function setInstallInfo($oldVersion = ''): array
    {
        UpgradeFunctions::setInstallInfo(self::getStoredVariant(), $oldVersion, DUPLICATOR____TYPE, DUPLICATOR_VERSION);
        /** @var array{version:string,time:int,updateTime:int} */
        return self::getStoredInstallInfo();
    }

    /**
     * Get install info.
     *
     * @return array{version:string,time:int,updateTime:int}
     */
    public static function getInstallInfo()
    {
        $installInfo = self::getStoredInstallInfo();
        if ($installInfo === false) {
            $installInfo = self::setInstallInfo();
        }
        return $installInfo;
    }
}
