<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magento\Framework\Setup\Declaration\Schema\Declaration\TableElement;

use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Setup\Declaration\Schema\Dto\Column;
use Magento\Framework\Setup\Declaration\Schema\Dto\Table;
use Magento\Framework\Setup\Declaration\Schema\TableNameResolver;

/**
 * Provide names of table elements with autogenerated names.
 */
class ElementNameResolver
{
    /**
     * @var TableNameResolver
     */
    private $tableNameResolver;

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @param TableNameResolver $tableNameResolver
     * @param ResourceConnection $resourceConnection
     */
    public function __construct(TableNameResolver $tableNameResolver, ResourceConnection $resourceConnection)
    {
        $this->tableNameResolver = $tableNameResolver;
        $this->resourceConnection = $resourceConnection;
    }

    /**
     * Provide the full index name based on the prefix value.
     *
     * @param Table $table
     * @param string[] $columns
     * @param string $type
     * @return string
     */
    public function getFullIndexName(
        Table $table,
        array $columns,
        ?string $type = AdapterInterface::INDEX_TYPE_INDEX
    ): string {
        if (AdapterInterface::INDEX_TYPE_PRIMARY === $type) {
            return strtoupper(AdapterInterface::INDEX_TYPE_PRIMARY);
        }

        /**
         * Temporary solution.
         * @see MAGETWO-91365
         */
        $isIndexTypeOutOfList = false === array_search(
            $type,
            [AdapterInterface::INDEX_TYPE_FULLTEXT, AdapterInterface::INDEX_TYPE_UNIQUE]
        );
        if ($type && $isIndexTypeOutOfList) {
            $type = AdapterInterface::INDEX_TYPE_INDEX;
        }

        $tableName = $this->tableNameResolver->getNameOfOriginTable($table->getName());

        return $this->resourceConnection
            ->getIdxName(
                $tableName,
                $columns,
                $type
            );
    }

    /**
     * Provide the index name without prefix value.
     *
     * @param string $name
     * @param Table $table
     * @param string[] $columns
     * @param string $type
     * @return string
     */
    public function getIndexNameWithoutPrefix(
        string $name,
        Table $table,
        array $columns,
        ?string $type = AdapterInterface::INDEX_TYPE_INDEX
    ): string {
        if (AdapterInterface::INDEX_TYPE_PRIMARY === $type) {
            return strtoupper(AdapterInterface::INDEX_TYPE_PRIMARY);
        }

        $nameWithoutPrefix = $name;

        if ($this->resourceConnection->getTablePrefix()) {
            /**
             * Temporary solution.
             * @see MAGETWO-91365
             */
            $isIndexTypeOutOfList = false === array_search(
                $type,
                [AdapterInterface::INDEX_TYPE_FULLTEXT, AdapterInterface::INDEX_TYPE_UNIQUE]
            );
            if ($type && $isIndexTypeOutOfList) {
                $type = AdapterInterface::INDEX_TYPE_INDEX;
            }

            $nameWithoutPrefix = $this->resourceConnection
                ->getConnection($table->getResource())
                ->getIndexName(
                    $this->tableNameResolver->getNameOfOriginTable(
                        $table->getNameWithoutPrefix()
                    ),
                    $columns,
                    $type
                );
        }

        return $nameWithoutPrefix;
    }

    /**
     * Provide the full foreign key name based on the prefix value.
     *
     * @param Table $table
     * @param Column $column
     * @param Table $referenceTable
     * @param Column $referenceColumn
     * @return string
     */
    public function getFullFKName(
        Table $table,
        Column $column,
        Table $referenceTable,
        Column $referenceColumn
    ): string {
        $fkName = $this->resourceConnection
            ->getFkName(
                $this->tableNameResolver->getNameOfOriginTable($table->getName()),
                $column->getName(),
                $referenceTable->getName(),
                $referenceColumn->getName()
            );

        return $fkName;
    }

    /**
     * Provide the foreign key name without prefix value.
     *
     * @param string $name
     * @param Table $table
     * @param Column $column
     * @param Table $referenceTable
     * @param Column $referenceColumn
     * @return string
     */
    public function getFKNameWithoutPrefix(
        string $name,
        Table $table,
        Column $column,
        Table $referenceTable,
        Column $referenceColumn
    ): string {
        $nameWithoutPrefix = $name;

        if ($this->resourceConnection->getTablePrefix()) {
            $nameWithoutPrefix = $this->resourceConnection
                ->getConnection($table->getResource())
                ->getForeignKeyName(
                    $this->tableNameResolver->getNameOfOriginTable(
                        $table->getNameWithoutPrefix()
                    ),
                    $column->getName(),
                    $referenceTable->getNameWithoutPrefix(),
                    $referenceColumn->getName()
                );
        }

        return $nameWithoutPrefix;
    }
}
