<?php

namespace idoit\Module\Console\Steps\Addon;

use Exception;
use idoit\AddOn\AddonVerify;
use idoit\Module\Console\Steps\Message\ErrorLevel;
use idoit\Module\Console\Steps\Message\Messages;
use idoit\Module\Console\Steps\Message\StepMessage;
use idoit\Module\Console\Steps\Step;

class ExtractAddonIdentifierFromPackage implements Step
{
    /**
     * @var callable
     */
    private $callback;

    /**
     * @var string
     */
    private $path;

    /**
     * InstallAddonByPackage constructor.
     *
     * @param string   $path
     * @param callable $callback - callback to be called with the extracted identifier
     */
    public function __construct(string $path, callable $callback)
    {
        $this->path = $path;
        $this->callback = $callback;
    }

    /**
     * Get name of the step
     *
     * @return string
     */
    public function getName()
    {
        return 'Extract to ' . $this->path;
    }

    /**
     * Process the work
     *
     * @param Messages $messages
     *
     * @return mixed
     */
    public function process(Messages $messages)
    {
        // @see  ID-8566  Check for any package.json files.
        $bundlePackageFiles = glob($this->path . 'package-*.json');

        // Go sure that we have an array of package files.
        if (!is_array($bundlePackageFiles)) {
            $bundlePackageFiles = [];
        }

        if (empty($bundlePackageFiles) && file_exists($this->path . 'package.json')) {
            $bundlePackageFiles[] = $this->path . 'package.json';
        }

        if (count($bundlePackageFiles) === 0) {
            return false;
        }

        $addonChecker = new AddonVerify();
        $validPackages = [];

        foreach ($bundlePackageFiles as $bundlePackageFile) {
            $package = json_decode(file_get_contents($bundlePackageFile), true);

            if (!is_array($package) || ($package['type'] ?? '') !== 'addon' || !isset($package['identifier'])) {
                $messages->addMessage(new StepMessage($this, 'package file does not contain the valid package information', ErrorLevel::ERROR));

                return false;
            }

            // @see ID-9075 Check if the provided add-on is allowed in this i-doit version.
            if (!$addonChecker->canInstall($package['identifier'], $package['version'])) {
                $addonTitle = $package['title'] ?: ucfirst($package['identifier']);
                $compatibleVersion = $addonChecker->getCompatibleVersion($package['identifier']);
                $givenVersion = $package['version'];
                $messages->addMessage(new StepMessage($this, "{$addonTitle} can not be installed, please try to install at least version {$compatibleVersion} (you provided {$givenVersion})", ErrorLevel::ERROR));
                return false;
            }

            $validPackages[] = [
                'file' => $bundlePackageFile,
                'package' => $package,
            ];
        }

        // @see ID-9066 install addon only if the addon or all addons in a bundle can be installed
        foreach ($validPackages as $package) {
            if (!call_user_func($this->callback, $package['file'], $package['package']['identifier'], $messages)) {
                return false;
            }
        }

        return true;
    }
}
