<?php
/**
 * Copyright 2020 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.
 */
declare(strict_types=1);

namespace Sut\Domain\MRay\DTO\Module;

class Dependency
{
    private const FACTORY_NAMES = [
        'Factory::create' => '',
        'ExtensionFactory::create' => 'Interface'
    ];

    private const EXTENSION_CLASS_NAMES = [
        'Extension' => '',
    ];

    private const EXTENSION_INTERFACE_NAMES = [
        'ExtensionInterface' => 'Interface',
    ];

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

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

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

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

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

    /**
     * @var DependencyUsage[]
     */
    private $usages;

    /**
     * Dependency constructor.
     * @param string $fqn
     * @param string $type
     * @param string $realName
     * @param string $moduleName
     * @param string $package
     * @param DependencyUsage[] $usages
     */
    public function __construct(
        string $fqn,
        string $type,
        string $realName = '',
        string $moduleName = '',
        string $package = '',
        array $usages = []
    ) {
        $this->fqn = $fqn;
        $this->type = $type;
        $this->realName = $realName;
        $this->moduleName = $moduleName;
        $this->package = $package;
        $this->usages = $usages;
    }

    /**
     * @return string
     */
    public function getFqn(): string
    {
        return $this->fqn;
    }

    /**
     * @return string
     */
    public function getType(): string
    {
        return $this->type;
    }

    /**
     * @return string
     */
    public function getRealName(): string
    {
        return $this->realName;
    }

    /**
     * @return string
     */
    public function getModuleName(): string
    {
        return $this->moduleName;
    }

    /**
     * @return string
     */
    public function getPackage(): string
    {
        return $this->package;
    }

    /**
     * @return DependencyUsage[]
     */
    public function getUsages(): array
    {
        return $this->usages;
    }

    /**
     * @return string
     */
    public function getOriginalFactory(): string
    {
        return $this->fqnReplace($this->getFqn(), self::FACTORY_NAMES);
    }

    /**
     * @return string
     */
    public function getOriginalExtensionClass(): string
    {
        return str_replace('Api\Data', 'Model', $this->fqnReplace($this->getFqn(), self::EXTENSION_CLASS_NAMES));
    }

    /**
     * @return string
     */
    public function getOriginalExtensionInterface(): string
    {
        return $this->fqnReplace($this->getFqn(), self::EXTENSION_INTERFACE_NAMES);
    }

    /**
     * @param string $fqn
     * @param array $names
     * @return string
     */
    private function fqnReplace(string $fqn, array $names): string
    {
        foreach ($names as $autoGeneratedName => $replacer) {
            if ($this->stringEndsWith($fqn, $autoGeneratedName)) {
                return str_replace($autoGeneratedName, $replacer, $this->getFqn());
            }
        }
        return '';
    }

    /**
     * @param string $haystack
     * @param string $needle
     * @return bool
     */
    private function stringEndsWith(string $haystack, string $needle): bool
    {
        return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, - strlen($needle)));
    }
}
