<?php

namespace Drupal\materio_graphql\Plugin\GraphQL\SchemaExtension;

use Drupal\graphql\GraphQL\ResolverBuilder;
use Drupal\graphql\GraphQL\ResolverRegistryInterface;
use Drupal\graphql\GraphQL\Response\ResponseInterface;
use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase;
use Drupal\materio_graphql\GraphQL\Response\MaterioResponse;
use Drupal\Core\Url;

use GraphQL\Error\Error;

/**
 * @SchemaExtension(
 *   id = "materio_extension",
 *   name = "Materio extension",
 *   description = "Materio extension.",
 *   schema = "materio"
 * )
 */
class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {

  /**
   * {@inheritdoc}
   */
  public function registerResolvers(ResolverRegistryInterface $registry) {
    $builder = new ResolverBuilder();

    $this->addRouteResolver($registry, $builder);

    $this->addMateriau($registry, $builder);

    $this->addNote($registry, $builder);

    $this->addSearchResult($registry, $builder);

    $this->addSample($registry, $builder);

    $this->addArticle($registry, $builder);

    $this->addThematique($registry, $builder);

    $this->addCompany($registry, $builder);

    $this->addProduct($registry, $builder);

    $this->addVariation($registry, $builder);

    $this->addPrice($registry, $builder);

    $this->addAddress($registry, $builder);

    $this->addFilefield($registry, $builder);

    $this->addFile($registry, $builder);

    $this->addDate($registry, $builder);

    $this->addLink($registry, $builder);

    $this->addShowroom($registry, $builder);

    $this->addTag($registry, $builder);

    $this->addThesaurus($registry, $builder);

    $this->addVideolink($registry, $builder);

    $this->addImage($registry, $builder);

    // Response type resolver.
    $registry->addTypeResolver('Response', [
      __CLASS__,
      'resolveResponse',
    ]);
  }

  //  ___          _
  // | _ \___ _  _| |_ ___
  // |   / _ \ || |  _/ -_)
  // |_|_\___/\_,_|\__\___|
  protected function addRouteResolver(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    // Tell GraphQL how to resolve types of a common interface.
    $registry->addTypeResolver('NodeInterface', function ($value) {

      $path = explode('\\', get_class($value));
      $class = array_pop($path);

      if ($class === 'Node') {
        switch ($value->bundle()) {
          case 'article': return 'Article';
          case 'materiau': return 'Materiau';
          case 'thematique': return 'Thematique';
        }
      }
      throw new Error('Could not resolve content type.');
    });

    $registry->addFieldResolver('Query', 'route',
      $builder->compose(
        $builder->callBack(function($parent, $args){
          $t="t";
          return $parent;
        }),
        $builder->produce('route_load')
          ->map('path', $builder->fromArgument('path')),
        $builder->callBack(function($parent, $args){
          $t="t";
          return $parent;
        }),
        $builder->produce('route_entity')
          ->map('url', $builder->fromParent())
          ->map('language', $builder->fromArgument('lang')),
        $builder->callBack(function($parent, $args){
          $t="t";
          return $parent;
        })
    ));
  }

  //  __  __      _           _
  // |  \/  |__ _| |_ ___ _ _(_)__ _ _  _
  // | |\/| / _` |  _/ -_) '_| / _` | || |
  // |_|  |_\__,_|\__\___|_| |_\__,_|\_,_|
  protected function addMateriau(ResolverRegistryInterface $registry, ResolverBuilder $builder) {

    // $language = \Drupal::languageManager()->getCurrentLanguage()->getId();

    $registry->addFieldResolver('Query', 'materiau',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('node'))
        ->map('bundles', $builder->fromValue(['materiau']))
        ->map('id', $builder->fromArgument('id'))
        ->map('language', $builder->fromArgument('lang'))
    );

    $registry->addFieldResolver('Query', 'materiaux',
      $builder->produce('entity_load_multiple')
        ->map('type', $builder->fromValue('node'))
        // ->map('bundles', $builder->fromValue(['materiau']))
        ->map('ids', $builder->fromArgument('ids'))
        ->map('language', $builder->fromArgument('lang'))
    );

    $registry->addFieldResolver('Materiau', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Materiau', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Materiau', 'bundle',
      $builder->compose(
        $builder->produce('entity_bundle')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Materiau', 'path',
      $builder->compose(
        $builder->produce('entity_url')
          ->map('entity', $builder->fromParent()),
        $builder->produce('url_path')
          ->map('url', $builder->fromParent())
      )
    );

    $registry->addFieldResolver('Materiau', 'title',
      $builder->compose(
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Materiau', 'body',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('body.value'))
      );

    $registry->addFieldResolver('Materiau', 'short_description',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_short_description.value'))
      );

    $registry->addFieldResolver('Materiau', 'author',
      $builder->compose(
        $builder->produce('entity_owner')
          ->map('entity', $builder->fromParent()),
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    // https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md
    // https://blog.chrismitchellonline.com/posts/custom_graphql_data/

    $registry->addFieldResolver('Materiau', 'linked_materials',
      $builder->compose(
        $builder->produce('entity_reference')
          ->map('entity', $builder->fromParent())
          ->map('field', $builder->fromValue('field_linked_materials'))
      ));

    $registry->addFieldResolver('Materiau', 'linked_articles',
      $builder->compose(
        $builder->produce('entity_reference')
          ->map('entity', $builder->fromParent())
          ->map('field', $builder->fromValue('field_linked_articles'))
      ));

    $registry->addFieldResolver('Materiau', 'memo',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_memo.value'))
      );

    $registry->addFieldResolver('Materiau', 'images',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_materiau_images'))
      );

    $registry->addFieldResolver('Materiau', 'attachments',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_attachments'))
      );

    $registry->addFieldResolver('Materiau', 'videos',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_video'))
      );

    $registry->addFieldResolver('Materiau', 'tags',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_tags'))
      );

    $registry->addFieldResolver('Materiau', 'thesaurus',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_thesaurus'))
      );

    $registry->addFieldResolver('Materiau', 'manufacturer',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_manufacturer'))
      );

    $registry->addFieldResolver('Materiau', 'distributor',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_distributor'))
      );

    // $registry->addFieldResolver('Materiau', 'famille',
    //   $builder->produce('property_path')
    //     ->map('type', $builder->fromValue('entity:node'))
    //     ->map('value', $builder->fromParent())
    //     ->map('path', $builder->fromValue('field_famille.value'))
    //   );
    //
    // $registry->addFieldResolver('Materiau', 'index',
    //   $builder->produce('property_path')
    //     ->map('type', $builder->fromValue('entity:node'))
    //     ->map('value', $builder->fromParent())
    //     ->map('path', $builder->fromValue('field_index.value'))
    //   );

    $registry->addFieldResolver('Materiau', 'reference',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_reference.value'))
      );

    $registry->addFieldResolver('Materiau', 'samples',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_samples'))
      );

    $registry->addFieldResolver('Materiau', 'note',
      $builder->compose(
        $builder->callback(function($parent, $args){
          // get the current user id
          $user = \Drupal::currentUser()->id();
          // get the current material id
          $target = $parent->id();
          // query the note for these user AND material (if any)
          // if null, UI will create it with rest api
          $entity_storage = \Drupal::entityTypeManager()->getStorage('node');
          $query = $entity_storage->getQuery()
            ->condition('type', 'note')
            ->condition('uid', $user)
            ->condition('field_target', $target)
            ->accessCheck(TRUE);
          $results = $query->execute();
          // $test="test";
          return array_shift($results);
        }),
        $builder->produce('entity_load')
          ->map('type', $builder->fromValue('node'))
          ->map('bundle', $builder->fromValue('note'))
          ->map('id', $builder->fromParent())
      )
    );
  }

  //  _  _     _
  // | \| |___| |_ ___
  // | .` / _ \  _/ -_)
  // |_|\_\___/\__\___|
  protected function addNote(ResolverRegistryInterface $registry, ResolverBuilder $builder) {

    $registry->addFieldResolver('Note', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Note', 'contenu',
        $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_contenu.value'))
    );

    $registry->addFieldResolver('Note', 'bundle',
      $builder->compose(
        $builder->produce('entity_bundle')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Note', 'target',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_target.target_id'))
      );
  }

  //  ___                  _    ___             _ _
  // / __| ___ __ _ _ _ __| |_ | _ \___ ____  _| | |_
  // \__ \/ -_) _` | '_/ _| ' \|   / -_|_-< || | |  _|
  // |___/\___\__,_|_| \__|_||_|_|_\___/__/\_,_|_|\__|
  protected function addSearchResult(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    // Tell GraphQL how to resolve types of a common interface.
    $registry->addTypeResolver('SearchResultInterface', function ($value) {
      switch ($value->bundle()) {
        case 'materiau': return 'Materiau';
        case 'thematique': return 'Thematique';
      }
      throw new Error('Could not resolve content type.');
    });

    $registry->addFieldResolver('Query', 'searchresults',
        $builder->produce('entity_load_multiple')
          ->map('type', $builder->fromValue('node'))
          ->map('ids', $builder->fromArgument('ids'))
          ->map('language', $builder->fromArgument('lang'))
    );
  }

  //  ___                  _
  // / __| __ _ _ __  _ __| |___
  // \__ \/ _` | '  \| '_ \ / -_)
  // |___/\__,_|_|_|_| .__/_\___|
  //                 |_|
  protected function addSample(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Sample', 'showroom',
      $builder->callback(function($parent, $args){
        return \Drupal\taxonomy\Entity\Term::load($parent['target_id']);
      })
    );
    $registry->addFieldResolver('Sample', 'location',
      $builder->callback(function($parent, $args){
        return $parent['location'];
      })
    );
  }

  //    _       _   _    _
  //   /_\  _ _| |_(_)__| |___
  //  / _ \| '_|  _| / _| / -_)
  // /_/ \_\_|  \__|_\__|_\___|
  protected function addArticle(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'article',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('node'))
        ->map('bundles', $builder->fromValue(['article']))
        ->map('id', $builder->fromArgument('id'))
        ->map('language', $builder->fromArgument('lang'))
      );

    $registry->addFieldResolver('Article', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Article', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Article', 'path',
      $builder->compose(
        $builder->produce('entity_url')
          ->map('entity', $builder->fromParent()),
        $builder->produce('url_path')
          ->map('url', $builder->fromParent())
      )
    );

    $registry->addFieldResolver('Article', 'bundle',
      $builder->compose(
        $builder->produce('entity_bundle')
          ->map('entity', $builder->fromParent())
      ));


    $registry->addFieldResolver('Article', 'title',
      $builder->compose(
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Article', 'author',
      $builder->compose(
        $builder->produce('entity_owner')
          ->map('entity', $builder->fromParent()),
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Article', 'body',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('body.value'))
      );

    $registry->addFieldResolver('Article', 'memo',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_memo.value'))
      );
    // https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md
    // https://blog.chrismitchellonline.com/posts/custom_graphql_data/
    $registry->addFieldResolver('Article', 'linked_materials',
      // $builder->produce('entity_reference')
      //   ->map('entity', $builder->fromParent())
      //   ->map('field', $builder->fromValue('field_linked_materials'))
      //   // ->map('language', $builder->fromValue('fr')) // this is not working
      //   // ->map('language', $builder->produce('entity_language')
      //     // ->map('entity', $builder->fromParent())) // neither that

      // THIS USED TO WORK but not anymore :(
      // invalid language translation (fr) provided
      $builder->compose(
        $builder->callback(function($parent, $args){
          $linkedmaterials = $parent->get('field_linked_materials')->getValue();
          $nids = [];
          foreach ($linkedmaterials as $key => $value) {
            $nids[] = $value['target_id'];
          }
          $lang = $parent->language()->getId();
          $test="test";
          return [
            "ids" => $nids,
            "language" => $lang
          ];
        }),
        $builder->produce('entity_load_multiple')
          ->map('type', $builder->fromValue('node'))
          ->map('bundles', $builder->fromValue(['materiau']))
          ->map('ids', $builder->callback(function($parent, $args){
            return $parent['ids'];
          }))
          ->map('language', $builder->callback(function($parent, $args){
            return $parent['language'];
          }))
      )
    );

    $registry->addFieldResolver('Article', 'images',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_visuel'))
      );

    $registry->addFieldResolver('Article', 'videos',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_video'))
      );

    $registry->addFieldResolver('Article', 'tags',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_tags'))
      );

    $registry->addFieldResolver('Article', 'thesaurus',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_thesaurus'))
      );

    $registry->addFieldResolver('Article', 'showroom',
      $builder->compose(
        $builder->produce('entity_reference')
          ->map('entity', $builder->fromParent())
          ->map('field', $builder->fromValue('field_showroom')),
        $builder->callback(function ($items) {
            return $items[0];
          })
      ));

    $registry->addFieldResolver('Article', 'source',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_source'))
      );

    $registry->addFieldResolver('Article', 'date',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_date'))
      );
  }

  //  _____ _                   _   _
  // |_   _| |_  ___ _ __  __ _| |_(_)__ _ _  _ ___
  //   | | | ' \/ -_) '  \/ _` |  _| / _` | || / -_)
  //   |_| |_||_\___|_|_|_\__,_|\__|_\__, |\_,_\___|
  //                                    |_|
  protected function addThematique(ResolverRegistryInterface $registry, ResolverBuilder $builder) {

    $registry->addFieldResolver('Query', 'thematique',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('node'))
        // ->map('bundles', $builder->fromValue(['thematique']))
        ->map('id', $builder->fromArgument('id'))
    );

    $registry->addFieldResolver('Thematique', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Thematique', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Thematique', 'path',
      $builder->compose(
        $builder->produce('entity_url')
          ->map('entity', $builder->fromParent()),
        $builder->produce('url_path')
          ->map('url', $builder->fromParent())
      )
    );

    $registry->addFieldResolver('Thematique', 'bundle',
      $builder->compose(
        $builder->produce('entity_bundle')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Thematique', 'title',
      $builder->compose(
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Thematique', 'author',
      $builder->compose(
        $builder->produce('entity_owner')
          ->map('entity', $builder->fromParent()),
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Thematique', 'short_description',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_short_description.value'))
      );

    $registry->addFieldResolver('Thematique', 'body',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('body.value'))
      );

    $registry->addFieldResolver('Thematique', 'memo',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:node'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_memo.value'))
      );
    // https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md
    // https://blog.chrismitchellonline.com/posts/custom_graphql_data/
    $registry->addFieldResolver('Thematique', 'linked_materials',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_linked_materials'))
      );

    $registry->addFieldResolver('Thematique', 'images',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_visuel'))
      );

    $registry->addFieldResolver('Thematique', 'tags',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('field_tags'))
      );

  }

  //  ___
  // |_ _|_ __  __ _ __ _ ___
  //  | || '  \/ _` / _` / -_)
  // |___|_|_|_\__,_\__, \___|
  //                |___/
  protected function addImage(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Image', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Image', 'url',
      $builder->produce('image_url')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Image', 'alt',
      $builder->produce('property_path')
      ->map('type', $builder->fromValue('entity:node'))
      ->map('value', $builder->fromParent())
      ->map('path', $builder->fromValue('field_image.alt'))
      );

    $registry->addFieldResolver('Image', 'style_minicard',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('card_medium_half'))
      );

    $registry->addFieldResolver('Image', 'style_minicard_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('card_medium_half')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

    $registry->addFieldResolver('Image', 'style_linkedmaterialcard',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('linkedmaterial_card'))
      );

    $registry->addFieldResolver('Image', 'style_linkedmaterialcard_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('linkedmaterial_card')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

    $registry->addFieldResolver('Image', 'style_cardmedium',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('card_medium'))
      );

    $registry->addFieldResolver('Image', 'style_cardmedium_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('card_medium')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

    $registry->addFieldResolver('Image', 'style_cardfull',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('card_full'))
      );

    $registry->addFieldResolver('Image', 'style_cardfull_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('card_full')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

    $registry->addFieldResolver('Image', 'style_articlecardmedium',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('article_card_medium'))
      );

    $registry->addFieldResolver('Image', 'style_articlecardmedium_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('article_card_medium')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

    $registry->addFieldResolver('Image', 'style_hd',
      $builder->produce('image_derivative')
        ->map('entity', $builder->fromParent())
        ->map('style', $builder->fromValue('hd'))
      );

    $registry->addFieldResolver('Image', 'style_hd_url',
      $builder->compose(
        $builder->produce('image_derivative')
          ->map('entity', $builder->fromParent())
          ->map('style', $builder->fromValue('hd')),
        $builder->callback(function($parent, $args){
            return $parent['url'];
          })
      ));

  }

  // __   ___    _         _    _      _
  // \ \ / (_)__| |___ ___| |  (_)_ _ | |__
  //  \ V /| / _` / -_) _ \ |__| | ' \| / /
  //   \_/ |_\__,_\___\___/____|_|_||_|_\_\
  protected function addVideolink(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('VideoLink', 'url',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('field_item:video_embed_field'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('value'))
      );
  }

  //  _____ _
  // |_   _| |_  ___ ___ __ _ _  _ _ _ _  _ ___
  //   | | | ' \/ -_|_-</ _` | || | '_| || (_-<
  //   |_| |_||_\___/__/\__,_|\_,_|_|  \_,_/__/
  protected function addThesaurus(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'thesaurus',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('taxonomy_term'))
        ->map('bundles', $builder->fromValue(['thesaurus']))
        ->map('id', $builder->fromArgument('id'))
      );

    $registry->addFieldResolver('Thesaurus', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Thesaurus', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Thesaurus', 'name',
      $builder->produce('entity_label')
        ->map('entity', $builder->fromParent())
      );
  }

  //  _____
  // |_   _|_ _ __ _
  //   | |/ _` / _` |
  //   |_|\__,_\__, |
  //           |___/
  protected function addTag(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'tag',
     $builder->produce('entity_load')
       ->map('type', $builder->fromValue('taxonomy_term'))
       ->map('bundles', $builder->fromValue(['tags']))
       ->map('id', $builder->fromArgument('id'))
     );

    $registry->addFieldResolver('Tag', 'id',
     $builder->produce('entity_id')
       ->map('entity', $builder->fromParent())
     );

    $registry->addFieldResolver('Tag', 'uuid',
     $builder->produce('entity_uuid')
       ->map('entity', $builder->fromParent())
     );

    $registry->addFieldResolver('Tag', 'name',
     $builder->produce('entity_label')
       ->map('entity', $builder->fromParent())
     );
  }

  //  ___ _
  // / __| |_  _____ __ ___ _ ___  ___ _ __
  // \__ \ ' \/ _ \ V  V / '_/ _ \/ _ \ '  \
  // |___/_||_\___/\_/\_/|_| \___/\___/_|_|_|
  protected function addShowroom(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'showroom',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('taxonomy_term'))
        ->map('bundles', $builder->fromValue(['showroom']))
        ->map('id', $builder->fromArgument('id'))
      );

    $registry->addFieldResolver('Showroom', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Showroom', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Showroom', 'name',
      $builder->produce('entity_label')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Showroom', 'email',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_email.value'))
      );

    $registry->addFieldResolver('Showroom', 'address',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_address'))
      );

    $registry->addFieldResolver('Showroom', 'phone',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_phone.value'))
      );

  }

  //  _    _      _
  // | |  (_)_ _ | |__
  // | |__| | ' \| / /
  // |____|_|_||_|_\_\
  protected function addLink(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Link', 'url',
      $builder->callback(function ($parent, $args) {
        return isset($parent[0]) ? $parent[0]['uri'] : null;
      })
    );
    $registry->addFieldResolver('Link', 'title',
      $builder->callback(function ($parent, $args) {
        return isset($parent[0]) ? $parent[0]['title'] : null;
      })
    );
  }

  //  ___       _
  // |   \ __ _| |_ ___
  // | |) / _` |  _/ -_)
  // |___/\__,_|\__\___|
  protected function addDate(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Date', 'start',
      $builder->callback(function ($parent, $args) {
        return isset($parent[0]) ? $parent[0]['value'] : null;
      })
    );
    $registry->addFieldResolver('Date', 'end',
      $builder->callback(function ($parent, $args) {
        return isset($parent[0]) ? $parent[0]['end_value'] : null;
      })
    );
  }

  //  ___ _ _      __ _     _    _
  // | __(_) |___ / _(_)___| |__| |
  // | _|| | / -_)  _| / -_) / _` |
  // |_| |_|_\___|_| |_\___|_\__,_|
  protected function addFilefield(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Filefield', 'description',
      $builder->callback(function ($parent, $args) {
        return $parent['description'];
      })
    );
    $registry->addFieldResolver('Filefield', 'file',
      $builder->callback(function ($parent, $args) {
        return \Drupal\file\Entity\File::load($parent['target_id']);
      })
    );
  }

  //  ___ _ _
  // | __(_) |___
  // | _|| | / -_)
  // |_| |_|_\___|
  protected function addFile(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('File', 'url',
      $builder->callback(function ($parent, $args) {
        return $parent->url();
      })
    );

    $registry->addFieldResolver('File', 'filesize',
      $builder->callback(function ($parent, $args) {
        return $parent->getSize();
      })
    );

    $registry->addFieldResolver('File', 'filemime',
      $builder->callback(function ($parent, $args) {
        return $parent->getMimeType();
      })
    );

    $registry->addFieldResolver('File', 'filename',
      $builder->callback(function ($parent, $args) {
        return $parent->getFilename();
      })
    );

    $registry->addFieldResolver('File', 'fid',
      $builder->callback(function ($parent, $args) {
        return $parent->id();
      })
    );

    $registry->addFieldResolver('File', 'uuid',
      $builder->callback(function ($parent, $args) {
        return $parent->uuid();
      })
    );
  }

  //    _      _    _
  //   /_\  __| |__| |_ _ ___ ______
  //  / _ \/ _` / _` | '_/ -_|_-<_-<
  // /_/ \_\__,_\__,_|_| \___/__/__/
  protected function addAddress(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    // $addr_fields = [
    //   'langcode',
    //   'country_code',
    //   'administrative_area',
    //   'locality',
    //   'dependent_locality',
    //   'postal_code',
    //   'sorting_code',
    //   'address_line1',
    //   'address_line2',
    //   'organization',
    //   'given_name',
    //   'additional_name',
    //   'family_name'
    // ];
    //
    // foreach ($addr_fields as $key => $value) {
    //   $registry->addFieldResolver('Address', $value,
    //     $builder->callback(function ($parent, $args) {
    //       return $parent[0][$value];
    //     })
    //   );
    // }

    $registry->addFieldResolver('Address', 'langcode',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['langcode'];
     })
    );
    $registry->addFieldResolver('Address', 'country_code',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['country_code'];
     })
    );
    $registry->addFieldResolver('Address', 'administrative_area',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['administrative_area'];
     })
    );
    $registry->addFieldResolver('Address', 'locality',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['locality'];
     })
    );
    $registry->addFieldResolver('Address', 'dependent_locality',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['dependent_locality'];
     })
    );
    $registry->addFieldResolver('Address', 'postal_code',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['postal_code'];
     })
    );
    $registry->addFieldResolver('Address', 'sorting_code',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['sorting_code'];
     })
    );
    $registry->addFieldResolver('Address', 'address_line1',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['address_line1'];
     })
    );
    $registry->addFieldResolver('Address', 'address_line2',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['address_line2'];
     })
    );
    $registry->addFieldResolver('Address', 'organization',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['organization'];
     })
    );
    $registry->addFieldResolver('Address', 'given_name',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['given_name'];
     })
    );
    $registry->addFieldResolver('Address', 'additional_name',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['additional_name'];
     })
    );
    $registry->addFieldResolver('Address', 'family_name',
     $builder->callback(function ($parent, $args) {
       return $parent[0]['family_name'];
     })
    );
  }

  //   ___
  //  / __|___ _ __  _ __  __ _ _ _ _  _
  // | (__/ _ \ '  \| '_ \/ _` | ' \ || |
  //  \___\___/_|_|_| .__/\__,_|_||_\_, |
  //                |_|             |__/
  protected function addCompany(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'company',
     $builder->produce('entity_load')
       ->map('type', $builder->fromValue('taxonomy_term'))
       ->map('bundles', $builder->fromValue(['company']))
       ->map('id', $builder->fromArgument('id'))
     );

    $registry->addFieldResolver('Company', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
    );

    $registry->addFieldResolver('Company', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
    );

    $registry->addFieldResolver('Company', 'name',
      $builder->produce('entity_label')
        ->map('entity', $builder->fromParent())
    );

    $registry->addFieldResolver('Company', 'description',
      $builder->callback(function($parent, $args){
        return $parent->getDescription();
      })
    );

    // TODO: property_path helper
    // $props = [
    //   [
    //     "res" => "attachments",
    //     "type" => "entity:taxonomy_term",
    //     "path" => "field_attachments",
    //   ]
    // ]
    // foreach ($props as $key => $value) {
    //   $registry->addFieldResolver('Company', $value['res'],
    //    $builder->produce('property_path')
    //      ->map('type', $builder->fromValue('entity:taxonomy_term'))
    //      ->map('value', $builder->fromParent())
    //      ->map('path', $builder->fromValue('field_attachments'))
    //    );
    // }

    $registry->addFieldResolver('Company', 'attachments',
     $builder->produce('property_path')
       ->map('type', $builder->fromValue('entity:taxonomy_term'))
       ->map('value', $builder->fromParent())
       ->map('path', $builder->fromValue('field_attachments'))
     );

    $registry->addFieldResolver('Company', 'memo',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_memo.value'))
      );

    $registry->addFieldResolver('Company', 'note',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_note.value'))
      );

    $registry->addFieldResolver('Company', 'website',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_website'))
      );

    $registry->addFieldResolver('Company', 'departement',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_departement.value'))
      );

    $registry->addFieldResolver('Company', 'email',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_email.value'))
      );

    $registry->addFieldResolver('Company', 'address',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_address'))
      );

    $registry->addFieldResolver('Company', 'phone',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_public_phone.value'))
      );

    $registry->addFieldResolver('Company', 'infos',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:taxonomy_term'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_infos_from_company.value'))
      );
  }

  protected function addProduct(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    $registry->addFieldResolver('Query', 'product',
      $builder->produce('entity_load')
        ->map('type', $builder->fromValue('commerce_product'))
        // ->map('bundles', $builder->fromValue(['materiau']))
        ->map('id', $builder->fromArgument('id'))
      );

    $registry->addFieldResolver('Query', 'products',
      $builder->produce('entity_load_multiple')
        ->map('type', $builder->fromValue('commerce_product'))
        // ->map('bundles', $builder->fromValue(['materiau']))
        ->map('ids', $builder->fromArgument('ids'))
    );

    $registry->addFieldResolver('Product', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Product', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );


    $registry->addFieldResolver('Product', 'bundle',
      $builder->produce('entity_bundle')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Product', 'path',
      $builder->compose(
        $builder->produce('entity_url')
          ->map('entity', $builder->fromParent()),
        $builder->produce('url_path')
          ->map('url', $builder->fromParent())
      )
    );

    $registry->addFieldResolver('Product', 'title',
      $builder->compose(
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Product', 'body',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:commerce_product'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('body.value'))
      );

    $registry->addFieldResolver('Product', 'price_description',
        $builder->produce('property_path')
          ->map('type', $builder->fromValue('entity:commerce_product'))
          ->map('value', $builder->fromParent())
          ->map('path', $builder->fromValue('field_price_description.value'))
      );

    $registry->addFieldResolver('Product', 'variations',
      $builder->produce('entity_reference')
        ->map('entity', $builder->fromParent())
        ->map('field', $builder->fromValue('variations'))
      );
  }

  protected function addVariation(ResolverRegistryInterface $registry, ResolverBuilder $builder) {
    // $registry->addFieldResolver('Query', 'product',
    //   $builder->produce('entity_load')
    //     ->map('type', $builder->fromValue('commerce_product_variation'))
    //     // ->map('bundles', $builder->fromValue(['materiau']))
    //     ->map('id', $builder->fromArgument('id'))
    //   );

    // $registry->addFieldResolver('Query', 'product',
    //   $builder->produce('entity_load_multiple')
    //     ->map('type', $builder->fromValue('product'))
    //     // ->map('bundles', $builder->fromValue(['materiau']))
    //     ->map('ids', $builder->fromArgument('ids'))
    // );

    $registry->addFieldResolver('Variation', 'id',
      $builder->produce('entity_id')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Variation', 'uuid',
      $builder->produce('entity_uuid')
        ->map('entity', $builder->fromParent())
      );


    $registry->addFieldResolver('Variation', 'bundle',
      $builder->produce('entity_bundle')
        ->map('entity', $builder->fromParent())
      );

    $registry->addFieldResolver('Variation', 'path',
      $builder->compose(
        $builder->produce('entity_url')
          ->map('entity', $builder->fromParent()),
        $builder->produce('url_path')
          ->map('url', $builder->fromParent())
      )
    );

    $registry->addFieldResolver('Variation', 'title',
      $builder->compose(
        $builder->produce('entity_label')
          ->map('entity', $builder->fromParent())
      ));

    $registry->addFieldResolver('Variation', 'description',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:commerce_product_variation'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('field_description.value'))
      );

    $registry->addFieldResolver('Variation', 'subscription_type',
        $builder->produce('property_path')
          ->map('type', $builder->fromValue('entity:commerce_product_variation'))
          ->map('value', $builder->fromParent())
          ->map('path', $builder->fromValue('subscription_type.value'))
      );

    $registry->addFieldResolver('Variation', 'sku',
        $builder->produce('property_path')
          ->map('type', $builder->fromValue('entity:commerce_product_variation'))
          ->map('value', $builder->fromParent())
          ->map('path', $builder->fromValue('sku.value'))
      );

    $registry->addFieldResolver('Variation', 'price',
      $builder->produce('property_path')
        ->map('type', $builder->fromValue('entity:commerce_product_variation'))
        ->map('value', $builder->fromParent())
        ->map('path', $builder->fromValue('price'))
      );

    // product_id
    // list_price
    // billing_schedule
    // license_expiration
    // license_type
    // field_multiple
  }

  protected function addPrice(ResolverRegistryInterface $registry, ResolverBuilder $builder) {

    $registry->addFieldResolver('Price', 'value',
      $builder->compose(
        $builder->callback(function($parent, $args){
          return $parent[0]['number'];
        })
      ));

    $registry->addFieldResolver('Price', 'currency',
      $builder->compose(
        $builder->callback(function($parent, $args){
          return $parent[0]['currency_code'];
        })
      ));
  }
  /**
   * Resolves the response type.
   *
   * @param \Drupal\graphql\GraphQL\Response\ResponseInterface $response
   *   Response object.
   *
   * @return string
   *   Response type.
   *
   * @throws \Exception
   *   Invalid response type.
   */
  public static function resolveResponse(ResponseInterface $response): string {
    // Resolve content response.
    if ($response instanceof MateriauResponse) {
      return 'MateriauResponse';
    }
    throw new \Exception('Invalid response type.');
  }

}
