<?php

/**
 * @file
 * Farm Inventory module.
 */

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_entity_base_field_info().
 */
function farm_inventory_entity_base_field_info(EntityTypeInterface $entity_type) {
  \Drupal::moduleHandler()->loadInclude('farm_inventory', 'inc', 'farm_inventory.base_fields');
  switch ($entity_type->id()) {

    // Build asset base fields.
    case 'asset':
      return farm_inventory_asset_base_fields();

    // Build quantity base fields.
    case 'quantity':
      return farm_inventory_quantity_base_fields();

    default:
      return [];
  }
}

/**
 * Implements hook_inline_entity_form_entity_form_alter().
 */
function farm_inventory_inline_entity_form_entity_form_alter(array &$entity_form, FormStateInterface &$form_state) {

  // Bail if not a quantity inline entity form.
  if ($entity_form['#entity_type'] !== 'quantity') {
    return;
  }

  // Specify special validation for the inventory values.
  // Validation is needed because we cannot solely rely on FAPI #states,
  // partially because it is hard to target the entity browser form widget.
  $entity_form['#element_validate'][] = 'farm_inventory_quantity_entity_inline_form_validate';

  // Set the inventory_adjustment default value to N/A unless already provided.
  if (empty($entity_form['inventory_adjustment']['widget']['#default_value'])) {
    $entity_form['inventory_adjustment']['widget']['#default_value'] = '_none';
  }

  // Build a selector for the inventory adjustment input.
  // This is complicated because the input name depends on the delta value,
  // and whether or not it is an existing entity in the inline entity form.
  $parents = $entity_form['#parents'];
  $adjustment_identifier = $parents[0] . '[' . implode('][', array_slice($parents, 1)) . '][inventory_adjustment]';
  $inventory_adjustment_selector = ":input[name=\"$adjustment_identifier\"]";

  // Hide the inventory asset selector until an adjustment is selected.
  $entity_form['inventory_asset']['#states']['invisible'] = [
    $inventory_adjustment_selector => ['value' => '_none'],
  ];
}

/**
 * Custom validation callback for the quantity inline form.
 *
 * @param array $form
 *   The entity form array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The entity form state.
 */
function farm_inventory_quantity_entity_inline_form_validate(array &$form, FormStateInterface $form_state) {

  // Get the inline entity form values out of the entire entity form state.
  $quantity_form_values = $form_state->getValue($form['#parents']);

  // If a quantity was provided, validate correct inventory values are provided.
  if (!empty($quantity_form_values)) {
    $adjustment = $quantity_form_values['inventory_adjustment'];
    $asset = $quantity_form_values['inventory_asset']['target_id'];

    // Set error if an adjustment is provided without an asset.
    if (!empty($adjustment) && empty($asset)) {
      // Error is set on the inventory_adjustment field because form errors
      // are not highlighted when set on the entity browser widget.
      $form_state->setError($form['inventory_adjustment']['widget'], t('Inventory asset is required if an inventory adjustment is selected.'));
    }

    // Set error if an asset is provided without an adjustment.
    if (empty($adjustment) && !empty($asset)) {
      $form_state->setError($form['inventory_adjustment']['widget'], t('Inventory adjustment is required if an inventory asset is selected.'));
    }
  }
}

/**
 * Prepares quantity inventory information for display.
 *
 * Default template: quantity.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - elements: An associative array containing the quantity information and
 *     any fields attached to the quantity. Properties used:
 *     - #quantity: A \Drupal\quantity\Entity\Quantity object. Quantity entity.
 *   - attributes: HTML attributes for the containing element.
 */
function farm_inventory_preprocess_quantity(array &$variables) {

  /** @var \Drupal\quantity\Entity\QuantityInterface $quantity */
  $quantity = $variables['elements']['#quantity'];
  if (!empty($variables['content']['inventory_adjustment']) && !empty($variables['content']['inventory_asset'])) {

    // Do not render the inventory fields themselves.
    unset($variables['content']['inventory_adjustment']);
    unset($variables['content']['inventory_asset']);

    // Get the adjustment label.
    /** @var \Drupal\Core\Field\FieldItemListInterface $adjustment_field */
    $adjustment_field = $quantity->get('inventory_adjustment');
    $adjustment_values = $adjustment_field->getFieldDefinition()->getSetting('allowed_values');
    $adjustment = $adjustment_values[$adjustment_field->first()->value];

    // Get the inventory asset.
    $assets = $quantity->get('inventory_asset')->referencedEntities();
    $asset = reset($assets);

    // Render array of inventory info to display after the quantity.
    $inventory = [
      '#prefix' => '<span class="inventory">',
      '#suffix' => '</span>',
      '#markup' => '(' . t('@adjustment <a href=":url">@asset</a> inventory', ['@adjustment' => $adjustment, ':url' => $asset->toUrl()->toString(), '@asset' => $asset->label()]) . ')',
      '#weight' => 5,
    ];
    $variables['content']['inventory'] = $inventory;
  }
}
