<?php
/**
 * Copyright 2022 Adobe
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute this file in
 * accordance with the terms of the Adobe license agreement accompanying
 * it.
 */
namespace Sut\Domain\Compatibility\Analyzers\Db;

use Magento\Mray\MagentoApiIndex\Api\DbSchemaInfo;
use Sut\Domain\Compatibility\Analyzers\AnalyzerInterface;
use Sut\Domain\Issue\IssueFactory;
use Sut\Domain\MRay\DTO\Module;

class ConstraintAnalyzer implements AnalyzerInterface
{
    private const USAGES = [
        'added-constraint-referencing-core-table',
        'added-constraint-to-core-table',
        'extended-core-table-constraint'
    ];

    private const ISSUE_CODES = [
        'Added constraint conflicts with core constraint referenceId' => 7007,
        'Extended core table constraint does not exist' => 7008,
        'Core table referenced by constraint does not exist' => 7009,
        'Core table column referenced by constraint does not exist' => 7010
    ];

    /**
     * @var DbSchemaInfo
     */
    private $dbSchemaInfo;

    /**
     * @var IssueFactory
     */
    private $issueFactory;

    /**
     * @param IssueFactory $issueFactory
     * @param DbSchemaInfo $dbSchemaInfo
     */
    public function __construct(IssueFactory $issueFactory, DbSchemaInfo $dbSchemaInfo)
    {
        $this->issueFactory = $issueFactory;
        $this->dbSchemaInfo = $dbSchemaInfo;
    }

    /**
     * @inheritdoc
     */
    public function analyze(Module\Dependency $dependency, Module\DependencyUsage $usage, string $version): array
    {
        if ($dependency->getType() !== 'db') {
            return [];
        }

        if (!in_array($usage->getType(), self::USAGES)) {
            return [];
        }

        $tableIndexName = explode('.', $dependency->getRealName());
        if (count($tableIndexName) !== 2) {
            return [];
        }

        $tableName = reset($tableIndexName);
        $constraintName = end($tableIndexName);

        if ($usage->getType() === 'added-constraint-to-core-table'
            && $this->dbSchemaInfo->getConstraint($tableName, $constraintName, $version) !== null
        ) {
            return [$this->issueFactory->createIssue(
                self::ISSUE_CODES['Added constraint conflicts with core constraint referenceId'],
                [$dependency->getRealName(), $version],
                $usage->getPosition(),
                $usage->getFile()
            )];
        }

        if ($usage->getType() === 'extended-core-table-constraint'
            && $this->dbSchemaInfo->getConstraint($tableName, $constraintName, $version) === null
        ) {
            return [$this->issueFactory->createIssue(
                self::ISSUE_CODES['Extended core table constraint does not exist'],
                [$dependency->getRealName(), $version],
                $usage->getPosition(),
                $usage->getFile()
            )];
        }

        if ($usage->getType() === 'added-constraint-referencing-core-table'
            && isset($usage->getData()['referenceTable'])
            ) {
            $referenceTable = (string) $usage->getData()['referenceTable'];
            if ($this->dbSchemaInfo->getTable($referenceTable, $version) === null) {
                return [$this->issueFactory->createIssue(
                    self::ISSUE_CODES['Core table referenced by constraint does not exist'],
                    [$referenceTable, $dependency->getRealName(), $version],
                    $usage->getPosition(),
                    $usage->getFile()
                )];
            }
            if (isset($usage->getData()['referenceColumn'])
                && $this->dbSchemaInfo->getColumn(
                    $referenceTable,
                    (string) $usage->getData()['referenceColumn'],
                    $version
                ) === null
            ) {
                return [$this->issueFactory->createIssue(
                    self::ISSUE_CODES['Core table column referenced by constraint does not exist'],
                    [$referenceTable, $dependency->getRealName(), $version],
                    $usage->getPosition(),
                    $usage->getFile()
                )];
            }
        }

        return [];
    }
}
