<?php
/**
 * @author 1902 Software
 * @copyright Copyright © 2023 1902 Software (https://1902software.com/magento/)
 * @package WriteTextAI_WriteTextAI
 */

namespace WriteTextAI\WriteTextAI\Setup\Patch\Data;

use Magento\Authorization\Model\Acl\Role\Group as RoleGroup;
use Magento\Authorization\Model\ResourceModel\Role\CollectionFactory as RoleCollectionFactory;
use Magento\Authorization\Model\RoleFactory;
use Magento\Authorization\Model\RulesFactory;
use Magento\Authorization\Model\UserContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddReviewerRoleDataPatch implements DataPatchInterface
{
    public const REVIEWER_ROLE = 'WriteText.ai Reviewer';

    public const EXPECTED_RESOURCES = [
        'WriteTextAI_WriteTextAI::menu',
        'WriteTextAI_WriteTextAI::review',
        'WriteTextAI_WriteTextAI::api_transfer'
    ];

    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

    /**
     * @var RoleFactory
     */
    private $roleFactory;

    /**
     * @var RoleCollectionFactory
     */
    private $roleCollectionFactory;

    /**
     * @var RulesFactory
     */
    private $rulesFactory;

    /**
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param RoleFactory $roleFactory
     * @param RoleCollectionFactory $roleCollectionFactory
     * @param RulesFactory $rulesFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        RoleFactory $roleFactory,
        RoleCollectionFactory $roleCollectionFactory,
        RulesFactory $rulesFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->roleFactory = $roleFactory;
        $this->roleCollectionFactory = $roleCollectionFactory;
        $this->rulesFactory = $rulesFactory;
    }

    /**
     * Apply data patch
     *
     * @return void
     */
    public function apply()
    {
        $roleCollection = $this->roleCollectionFactory->create();
        $roleCollection->addFieldToFilter('role_name', self::REVIEWER_ROLE);
        $roleCollection->setOrder('role_id', 'DESC');

        $role = $roleCollection->getFirstItem();

        if (!$role || !$role->getId()) {
            $role = $this->roleFactory->create();
            $role->setName(self::REVIEWER_ROLE)
                ->setPid(0)
                ->setRoleType(RoleGroup::ROLE_TYPE)
                ->setUserType(UserContextInterface::USER_TYPE_ADMIN);
            $role->save();
        }

        if ($this->doRulesMatch((int) $role->getId(), self::EXPECTED_RESOURCES)) {
            return;
        }

        $connection = $this->moduleDataSetup->getConnection();
        $connection->delete(
            $this->moduleDataSetup->getTable('authorization_rule'),
            ['role_id = ?' => (int) $role->getId()]
        );

        $this->rulesFactory->create()
            ->setRoleId((int) $role->getId())
            ->setResources(self::EXPECTED_RESOURCES)
            ->saveRel();
    }

    /**
     * Check if rules match expected resources
     *
     * @param int $roleId
     * @param array $expectedResources
     * @return bool
     */
    private function doRulesMatch(int $roleId, array $expectedResources): bool
    {
        $connection = $this->moduleDataSetup->getConnection();
        $select = $connection->select()
            ->from($this->moduleDataSetup->getTable('authorization_rule'), ['resource_id'])
            ->where('role_id = ?', $roleId);

        $currentResources = $connection->fetchCol($select);

        sort($currentResources);
        sort($expectedResources);

        return $currentResources === $expectedResources;
    }

    /**
     * Get dependencies
     *
     * @return array
     */
    public static function getDependencies()
    {
        return [
            ApplyWriteTextAiDataPatch::class
        ];
    }

    /**
     * Get aliases
     *
     * @return array
     */
    public function getAliases()
    {
        return [];
    }
}
