<?php

/**
 * @file
 * Contains \Drupal\npq\Form\NodePublisherQueueForm.
 */

namespace Drupal\images_styles_gen\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Queue\QueueInterface;
use Drupal\Core\Queue\QueueWorkerInterface;
use Drupal\Core\Queue\QueueWorkerManagerInterface;
use Drupal\Core\Queue\SuspendQueueException;
use Symfony\Component\DependencyInjection\ContainerInterface;

class ImgStylesGenQueueForm extends FormBase {

  /**
   * @var QueueFactory
   */
  protected $queueFactory;

  /**
   * @var QueueWorkerManagerInterface
   */
  protected $queueManager;


  /**
   * {@inheritdoc}
   */
  public function __construct(QueueFactory $queue, QueueWorkerManagerInterface $queue_manager) {
    $this->queueFactory = $queue;
    $this->queueManager = $queue_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('queue'),
      $container->get('plugin.manager.queue_worker')
    );
  }

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'images_styles_gen_form';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style');

    $content_type_id = $form_state->getValue('node_type');
    $style_id = $form_state->getValue('style');
    $batch_size = (int)$form_state->getValue('batch_size');

    $num_rows = 0;
    if ( $content_type_id && $style_id ) {

      $database = \Drupal::database();
      $query = $database->select('file_managed', 'fm');
      $query->join('file_usage', 'fu', 'fm.fid = fu.fid');
      $query->join('node', 'n', 'fu.id = n.nid');
      $query
        ->condition('fm.filemime', 'image/%', 'LIKE')
        ->condition('fu.type', 'node')
        ->condition('n.type', $content_type_id)
        ->fields('fm', ['fid', 'uri'])
        ->fields('fu', ['id']);

      $results = $query->execute();

      /** @var \Drupal\image\Entity\ImageStyle $style */
      $style = $styles_storage->load($style_id);

      foreach ($results as $file) {
        $destination = $style->buildUri($file->uri);
        if (file_exists($destination)) continue; // if destination exists skip
        $num_rows++;
      }
    }


    // select from content type we'll generate derivatives
    $contentTypes = \Drupal::service('entity.manager')->
    getStorage('node_type')->loadMultiple();
    $contentTypesList = [0 => "please choose a content type"];
    foreach ($contentTypes as $contentType) {
        $contentTypesList[$contentType->id()] = $contentType->label();
    }
    $form['node_type'] = array(
      "#type" => "select",
      "#title" => "Content type",
      '#options' => $contentTypesList,
      '#ajax' => [
        'callback' => '::countAjaxCallback', // don't forget :: when calling a class method.
        //'callback' => [$this, 'myAjaxCallback'], //alternative notation
        'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element.
        'event' => 'change',
        'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback.
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('counting entries...'),
        ],
      ]
    );

    // select for which style will generate derivatives
    $styles = $styles_storage->loadMultiple(); //, 'card_full', 'linkedmaterial_card'
    $stylesList = [0 => "please choose a style"];
    foreach ($styles as $style) {
        $stylesList[$style->id()] = $style->label();
    }
    $form['style'] = array(
      "#type" => "select",
      "#title" => "Images Styles",
      '#options' => $stylesList,
      '#ajax' => [
        'callback' => '::countAjaxCallback', // don't forget :: when calling a class method.
        //'callback' => [$this, 'myAjaxCallback'], //alternative notation
        'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element.
        'event' => 'change',
        'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback.
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('counting entries...'),
        ],
      ]
    );

    $form['batch_size'] = array(
      '#type' => 'select',
      '#title' => 'Batch size',
      '#options' => array(
        10 => '10',
        100 => '100',
        500 => '500',
        1000 => '1000',
        50000 => '5000',
        10000 => '10000',
        0 => 'no limit'
      ),
      '#ajax' => [
        'callback' => '::countAjaxCallback', // don't forget :: when calling a class method.
        //'callback' => [$this, 'myAjaxCallback'], //alternative notation
        'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element.
        'event' => 'change',
        'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback.
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('counting entries...'),
        ],
      ]
    );

    $form['help-wrapper'] = array(
      '#type' => 'container'
    );

    $form['help-wrapper']['help'] = array(
      '#type' => 'markup',
      // '#prefix' => '<div>',
      '#markup' => $this->t('Please choose a content type and a style.'),
      // '#suffix' => '</div>',
      '#attributes' => array(
        'id' => 'help'
      )
    );

    if ($num_rows) {
      if($batch_size == 0){
        $batch_size = $num_rows;
      }
      $form['help-wrapper']['help']['#markup'] = $this->t('Submitting this form will process @batch_size of @number images.', array('@batch_size' => $batch_size, '@number' => $num_rows));
      // $form['actions']['submit']['#disabled'] = FALSE;
      // unset($form['actions']['submit']['#attributes']['disabled']);
    }

    $form['help-wrapper']['num_rows'] = array(
      '#type' => 'hidden',
      '#value' => $num_rows,
    );

    // Actions
    $form['actions']['#type'] = 'actions';

    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Create image derivatives'),
      '#button_type' => 'primary',
      // '#disabled' => true,
      '#states' => [
        //show this submit only if the num rows is not empty
        'visible' => [
          //don't mistake :input for the type of field. You'll always use
          //:input here, no matter whether your source is a select, radio or checkbox element.
          ':input[name="num_rows"]' => ['!value' => 0],
        ],
      ],
    );

    return $form;
  }

  // Get the value from example select field and fill
  // the textbox with the selected text.
  public function countAjaxCallback(array &$form, FormStateInterface $form_state) {
    $form['help-wrapper']['#id'] = 'edit-help-wrapper';
    return $form['help-wrapper'];
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $content_type_id = $form_state->getValue('node_type');
    $style_id = $form_state->getValue('style');
    $batch_size = (int)$form_state->getValue('batch_size');

    $database = \Drupal::database();
    $query = $database->select('file_managed', 'fm');
    $query->join('file_usage', 'fu', 'fm.fid = fu.fid');
    $query->join('node', 'n', 'fu.id = n.nid');
    $query
      ->condition('fm.filemime', 'image/%', 'LIKE')
      ->condition('fu.type', 'node')
      ->condition('n.type', $content_type_id)
      ->fields('fm', ['fid', 'uri'])
      ->fields('fu', ['id']);

    $results = $query->execute();

    $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style');
    /** @var \Drupal\image\Entity\ImageStyle $style */
    $style = $styles_storage->load($style_id);

    $operations = [];
    foreach ($results as $file) {
      $destination = $style->buildUri($file->uri);

      if (file_exists($destination)) continue; // skip existing files

      $batch_item = new \stdClass();
      $batch_item->style = $style;
      $batch_item->uri = $file->uri;
      $batch_item->destination = $destination;

      $operations[] = ['\Drupal\images_styles_gen\CreateImagesStyles::createStyles', [$batch_item]];

      if($batch_size && count($operations) >= $batch_size){
        break;
      }
    }

    $batch = array(
      'title' => t('Creating images derivatives ...'),
      'operations' => $operations,
      'finished' => '\Drupal\images_styles_gen\CreateImagesStyles::createStylesFinishedCallback',
    );

    batch_set($batch);
  }
}
