<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Components\Migration;

/**
 * A MigrationSet Holds a bunch of ManifestedMigrations.
 *
 * Its intention is to ensure that all the migrations in it are dependent one of another. They can only be executed in
 * the order like they were added to the set and no migration can be executed before every other migration before it
 * has either the status 'success' or returns false for canExecute().
 */
class MigrationSet
{
    /**
     * @var string
     */
    private $name;

    /**
     * @var ManifestedMigration[]
     */
    private $migrations = [];

    /**
     * @var string[] Contains the lower case names of all migrations in this set
     */
    private $migrationNames = [];

    /**
     * @param string $name
     */
    public function __construct($name)
    {
        $this->name = $name;
    }

    /**
     * @param string $name
     * @param Migration $migration
     */
    public function add($name, Migration $migration)
    {
        $lowerCaseName = mb_strtolower($name);
        if (in_array($lowerCaseName, $this->migrationNames, true)) {
            throw new \InvalidArgumentException(
                sprintf('Migration with name "%s" already exists in this MigrationSet.', $name)
            );
        }

        $this->migrationNames[] = $lowerCaseName;
        $this->migrations[] = new ManifestedMigration($name, $migration);
    }

    /**
     * Returns whether there is at least one pending migration.
     *
     * A pending migrations is one that return true for canExecute() and does not have the status 'success'
     *
     * @return bool
     */
    public function hasExecutableMigrations()
    {
        return count($this->getExecutableMigrations()) !== 0;
    }

    /**
     * @return ManifestedMigration[]
     */
    public function getExecutableMigrations()
    {
        return array_values(array_filter(
            $this->migrations,
            function (ManifestedMigration $migration) {
                return $migration->canExecute() && $migration->getStatus() !== ManifestedMigration::STATUS_COMPLETED;
            }
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return ManifestedMigration[]
     */
    public function getMigrations()
    {
        return $this->migrations;
    }
}
