<?php

declare(strict_types=1);

namespace KupShop\GraphQLBundle\Util;

use GraphQL\Type\Schema;
use KupShop\GraphQLBundle\Util\Locator\GraphQLLocator;

class SchemaFactory
{
    public const TYPE_ADMIN = 'admin';
    public const TYPE_POS = 'pos';

    public function __construct(
        protected readonly GraphQLFactory $graphQLFactory,
        protected readonly Schema $publicSchema,
        private readonly GraphQLLocator $locator,
    ) {
    }

    public function createAdminSchema(): Schema
    {
        return $this->create(self::TYPE_ADMIN);
    }

    public function createPosSchema(): Schema
    {
        return $this->create(self::TYPE_POS);
    }

    public function createPublicSchema(): Schema
    {
        return $this->publicSchema;
    }

    private function create(string $type): Schema
    {
        if (!in_array($type, [self::TYPE_ADMIN, self::TYPE_POS])) {
            throw new \RuntimeException("Schema type `{$type}` is not supported!");
        }

        $controllers = $this->locator->getControllerNamespaces($type);
        $types = $this->locator->getTypeNamespaces($type);

        // backward compatibility - deprecated!!
        if ($type === self::TYPE_ADMIN) {
            if (!empty($this->graphQLFactory->adminConfig['additional_controllers']) || !empty($this->graphQLFactory->adminConfig['additional_types'])) {
                $controllers = array_merge($controllers, $this->graphQLFactory->adminConfig['additional_controllers'] ?? []);
                $types = array_merge($types, $this->graphQLFactory->adminConfig['additional_types'] ?? []);
            }
        }

        $factory = $this->graphQLFactory->createSchemaFactory($controllers, $types);

        foreach ($this->locator->getFieldMiddlewares($type) as $fieldMiddleware) {
            $factory->addFieldMiddleware($fieldMiddleware);
        }

        foreach ($this->locator->getInputFieldMiddlewares($type) as $inputFieldMiddleware) {
            $factory->addInputFieldMiddleware($inputFieldMiddleware);
        }

        foreach ($this->locator->getTypeMapperFactories($type) as $typeMapperFactory) {
            $factory->addTypeMapperFactory($typeMapperFactory);
        }

        return $factory->createSchema();
    }
}
