<?php

namespace Drupal\people_rest\Plugin\rest\resource;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\node\Entity\Node;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Psr\Log\LoggerInterface;

/**
 * Provides a resource to get people
 *
 * @RestResource(
 *   id = "rest_people",
 *   label = @Translation("Peoples"),
 *   uri_paths = {
 *     "canonical" = "/api/people",
 *     "create" = "/api/people/create"
 *   }
 * )
 */
class Peoples extends ResourceBase {
  public $number_page;
  private $path;
  private $max_page;
  private $nodes;
  private $allow_fields;
  private $allow_fields_reference;
  private $cache;

  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
    $number_page = \Drupal::request()->get('page');
    $host = \Drupal::request()->getSchemeAndHttpHost();
    $alias = \Drupal::service('path.current')->getPath();
    $path = $host . $alias;
    $this->number_page = isset($number_page) ? $number_page : 1;
    $this->path = $path;
    $this->nodes = $this->loadNodes();
    $this->max_page = ceil((int)count($this->nodes)/10);
    $this->allow_fields = ['height', 'mass', 'hair_color', 'skin_color', 'birth_year', 'gender'];
    $this->allow_fields_reference = ['films', 'species', 'vehicles', 'starships'];
    $this->cache = new CacheableMetadata();
  }

  public function get() {
    $response = new ResourceResponse('404 Not Found', 404);
    if ($this->validPage()) {
      $response['count'] = count($this->nodes);
      $response['next'] = $this->getNext();
      $response['previous'] = $this->getPrevious();
      $response['results'] = $this->getResults($this->number_page);
      $response = new ResourceResponse($response, 200);
      $this->cache->setCacheMaxAge(900);
      $this->cache->setCacheContexts(['url.query_args']);
      $response->addCacheableDependency($this->cache);
    }
    return $response;
  }

  public function post($data) {
    if ($data['swapi_id']) {
      $node = \Drupal::entityTypeManager()
        ->getStorage('node')
        ->loadByProperties(['type' => 'people', 'field_swapi_id' => $data['swapi_id']]);
      if (!empty($node)) {
        return new ResourceResponse(['Нода с таким swapi_id уже существует!']);
      }
      if (isset($data['name'])) {
        $node = Node::create([
          'type' => 'people',
          'title' => $data['name']
        ]);
        foreach($data as $key => $value) {
          if ($key == 'name') {
            continue;
          }
          $field_name = "field_" . $key;
          if ($node->hasField($field_name)) {
            $node->set($field_name, $value);
          } else {
            return new ResourceResponse(["$field_name данное поле не найдено"]);
          }
        }
        $node->save();
        return new ResourceResponse(["Нода с названием {$data['name']} успешно создана"]);
      } else {
        return new ResourceResponse(['Укажите обязательное поле name!']);
      }
    } else {
      return new ResourceResponse(['Укажите обязательное поле swapi_id!']);
    }
  }

  public function getResults($page) {
    $nodes = $this->nodes;
    $cache = $this->cache;
    $start_index = ($page * 10) - 10;
    ($page == $this->max_page) ? $last_index = count($nodes) : $last_index = $page * 10;
    for ($i = $start_index; $i < $last_index; $i++) {
      $node = $nodes[$i];
      $item['title'] = $node->label();
      foreach ($this->allow_fields as $field) {
        $item[$field] = $this->getFieldValue("field_$field", $node);
      }

      $node_homeworld = current($node->get('field_homeworld')->referencedEntities());
      $item['homeworld'] = ['nid' => $node_homeworld->id(), 'title' => $node_homeworld->label()];

      foreach ($this->allow_fields_reference as $field) {
        $item[$field] = $this->getFieldReference("field_$field", $node);
      }

      $created = $node->get('created')->getValue();
      $item['created'] = date("Y-m-d H:i:s", (int)$created[0]['value']);
      $changed = $node->get('changed')->getValue();
      $item['edited'] = date("Y-m-d H:i:s", (int)$changed[0]['value']);
      $url = $node->toUrl()->setAbsolute()->toString(TRUE);
      $item['url'] = $url->getGeneratedUrl();
      $results[] = $item;
      $cache->addCacheableDependency($node);
    }
    return $results;
  }

  public function getFieldReference($filed_name, $node) {
    $references = $node->get($filed_name)->referencedEntities();
    $values = [];
    foreach ($references as $reference) {
      $this->cache->addCacheableDependency($reference);
      $values[] = ['nid' => $reference->id(), 'title' => $reference->label()];
    }
    return $values;
  }

  public function getFieldValue($field_name, $node) {
    $field_value = $node->get($field_name)->getValue();
    $field_value = $field_value[0]['value'];
    return $field_value;
  }

  public function getNext() {
    if ($this->number_page == $this->max_page) {
      $path = null;
    } else {
      $path = $this->path . "?page=" . ($this->number_page + 1);
    }
    return $path;
  }

  public function getPrevious() {
    if ($this->number_page == 1) {
      $path = null;
    } else {
      $path = $this->path . "?page=" . ($this->number_page - 1);
    }
    return $path;
  }

  public function validPage() {
    if ($this->number_page <= $this->max_page && $this->number_page > 0)
      return true;
  }

  public function loadNodes() {
    $nodes = \Drupal::entityTypeManager()
      ->getStorage('node')
      ->loadByProperties(['type' => 'people']);
    $nodes = array_values($nodes);
    return $nodes;
  }
}
