<?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\Classes\Installation\AttributeColumn;

use InvalidArgumentException;
use Shopware\Components\Model\ModelManager;
use Shopware\Plugins\ViisonCommon\Classes\Installation\SQLHelper;

class AttributeColumnInstaller
{
    /**
     * @var ModelManager
     */
    private $entityManager;

    /**
     * @var SQLHelper
     */
    private $sqlHelper;

    /**
     * @param ModelManager $entityManager
     * @param SQLHelper $sqlHelper
     */
    public function __construct(ModelManager $entityManager, SQLHelper $sqlHelper)
    {
        $this->entityManager = $entityManager;
        $this->sqlHelper = $sqlHelper;
    }

    /**
     * @param AttributeColumnDescription[]
     * @throws InvalidArgumentException if one of the passed elements is not of type AttributeColumnDescription or
     *                                  its data is invalid.
     */
    public function addAttributeColumnsIfNotExist(array $attributeColumnDescriptions)
    {
        $updatedTables = [];
        foreach ($attributeColumnDescriptions as $columnDescription) {
            // Validate the column description
            if (!($columnDescription instanceof AttributeColumnDescription)) {
                throw new InvalidArgumentException('The passed column description must be of type AttributeColumnDescription.');
            }
            $columnType = $columnDescription->getColumnType();
            if (empty($columnType)) {
                throw new InvalidArgumentException(sprintf(
                    'Cannot add attribute column "%s" to table "%s" without a valid type (given: "%s").',
                    $columnDescription->getColumnName(),
                    $columnDescription->getTableName(),
                    $columnDescription->getColumnType()
                ));
            }
            if (!$columnDescription->isNullable() && $columnDescription->getDefaultValue() === null) {
                throw new InvalidArgumentException(sprintf(
                    'Cannot add attribute column "%s" to table "%s", because it is defined as not nullable but does not provide a default value.',
                    $columnDescription->getColumnName(),
                    $columnDescription->getTableName()
                ));
            }

            // Build the column specification
            $columnSpecification = $columnType;
            if (!$columnDescription->isNullable()) {
                $columnSpecification .= ' NOT NULL';
            }
            if ($columnDescription->getDefaultValue() === null) {
                $columnSpecification .= ' DEFAULT NULL';
            } else {
                $defaultValue = $columnDescription->getDefaultValue();
                if (is_bool($defaultValue)) {
                    $defaultValue = ($defaultValue) ? '1' : '0';
                }
                $columnSpecification .= sprintf(' DEFAULT \'%s\'', $defaultValue);
            }

            // Create the column
            $this->sqlHelper->addColumnIfNotExists(
                $columnDescription->getTableName(),
                $columnDescription->getColumnName(),
                $columnSpecification
            );
            $updatedTables[] = $columnDescription->getTableName();
        }

        $this->entityManager->generateAttributeModels($updatedTables);
    }
}
