<?php
/**
 * This file is part of the DATAtourisme project.
 *
 *  @author Conjecto <contact@conjecto.com>
 *
 * For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
 */

namespace Datatourisme\Api\Schema;

use Datatourisme\Api\Exception\RuntimeException;
use Datatourisme\Api\Resolver\ResolverInterface;
use Datatourisme\Api\Schema\Compiler\SchemaCompiler;
use Youshido\GraphQL\Config\Schema\SchemaConfig;
use Youshido\GraphQL\Execution\ResolveInfo;
use Youshido\GraphQL\Type\ListType\ListType;
use Youshido\GraphQL\Type\Object\ObjectType;
use Youshido\GraphQL\Type\Scalar\FloatType;
use Youshido\GraphQL\Type\Scalar\IntType;
use Youshido\GraphQL\Type\Scalar\StringType;

abstract class AbstractSchema extends \Youshido\GraphQL\Schema\AbstractSchema
{
    /**
     * @return mixed
     */
    abstract public function getNamespace();

    /**
     * @return PrefixMap
     */
    abstract public function getPrefixMap();

    /**
     * @param SchemaConfig $config
     */
    public function build(SchemaConfig $config)
    {
        //unused
    }

    /**
     * @param $name
     * @param $entrypoint
     * @param ResolverInterface $resolver
     */
    public function addEntryPoint($name, $entrypoint, ResolverInterface $resolver)
    {
        $typeClass = '\\'.$this->getNamespace().'\Type_'.SchemaCompiler::normalize($entrypoint);
        $sortTypeClass = '\\'.$this->getNamespace().'\SortType_'.SchemaCompiler::normalize($entrypoint);
        $filterTypeClass = '\\'.$this->getNamespace().'\FilterType_'.SchemaCompiler::normalize($entrypoint);

        if (!class_exists($typeClass)) {
            throw new RuntimeException("The entrypoint type $entrypoint is unknown.");
        }

        $this->addQueryField($name, [
            'type' => new ObjectType([
                'name' => SchemaCompiler::normalize($entrypoint).'_ResultSet',
                'fields' => [
                    'total' => new IntType(),
                    'results' => new ListType(new $typeClass()),
                    'query' => new StringType(),
                    'stats' => new ObjectType([
                        'name' => 'Statistics',
                        'fields' => [
                            'execution' => new FloatType(),
                            'count' => new FloatType(),
                            'hydration' => new FloatType(),
                            'total' => new FloatType(),
                        ],
                    ]),
                ],
            ]),
            'args' => [
                'uri' => new StringType(),
                'size' => new IntType(),
                'from' => new IntType(),
                'sort' => new ListType(new $sortTypeClass()),
                'filters' => new ListType(new $filterTypeClass()),
                'lang' => new StringType(),
            ],
            'resolve' => function ($values, $args, ResolveInfo $info) use ($resolver, $entrypoint) {
                return $resolver->resolve($entrypoint, $args, $info);
            },
        ]);
    }

    /**
     * @param $uri
     *
     * @return string
     */
    public function expandUri($uri)
    {
        return $this->getPrefixMap()->expandUri($uri);
    }

    /**
     * @param $uri
     *
     * @return string
     */
    public function shortenUri($uri)
    {
        return $this->getPrefixMap()->shortenUri($uri);
    }
}
