<?php

declare(strict_types=1);

namespace Drupal\sobki_tablefield\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ui_patterns\Plugin\Context\RequirementsContext;
use Drupal\ui_patterns_field_formatters\Plugin\Field\FieldFormatter\ComponentPerItemFormatter;

/**
 * Plugin implementation of the Sobki Tablefield formatter.
 */
#[FieldFormatter(
  id: 'sobki_tablefield',
  label: new TranslatableMarkup('Sobki Tabular View'),
  field_types: [
    'tablefield',
  ],
)]
class SobkiTablefieldFormatter extends ComponentPerItemFormatter {

  public const string TABLE_COMPONENT = 'ui_suite_bootstrap:table';

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    $settings = parent::defaultSettings();
    $settings['row_header'] = TRUE;
    $settings['column_header'] = FALSE;
    return $settings;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $form['row_header'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Display first row as a table header'),
      '#default_value' => $this->getSetting('row_header'),
    ];
    $form['column_header'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Display first column as a table header'),
      '#default_value' => $this->getSetting('column_header'),
    ];

    /** @var \Drupal\Core\Plugin\Context\ContextInterface[] $injected_contexts */
    $injected_contexts = $this->getComponentSourceContexts();
    // Here we need to propagate the information
    // that in the parent field_formatter hierarchy
    // The current field value has been treated in a per item manner
    // Thus, when source plugins will be fetched and displayed,
    // we properly get them especially source plugins
    // with context_requirements having field_granularity:item.
    if (\is_array($this->context)
      && \array_key_exists('context_requirements', $this->context)
      && $this->context['context_requirements'] instanceof RequirementsContext
      && $this->context['context_requirements']->hasValue('field_granularity:item')
    ) {
      $injected_contexts = RequirementsContext::addToContext(['field_granularity:item'], $injected_contexts);
    }
    $form['ui_patterns'] = $this->buildComponentsForm(
      $form_state,
      $injected_contexts,
      static::TABLE_COMPONENT,
      FALSE,
    );
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = parent::settingsSummary();

    $row_header = $this->getSetting('row_header');
    if ($row_header) {
      $summary[] = (string) $this->t('First row as a table header');
    }

    $column_header = $this->getSetting('column_header');
    if ($column_header) {
      $summary[] = $this->t('First column as a table header');
    }

    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    // Workaround component ID not saved. So we can directly call parent method.
    $settings = $this->getSettings();
    $settings['ui_patterns']['component_id'] = static::TABLE_COMPONENT;
    $this->setSettings($settings);
    $build = parent::viewElements($items, $langcode);

    // Construct slots manually.
    $row_header = $this->getSetting('row_header');
    $column_header = $this->getSetting('column_header');
    /** @var \Drupal\tablefield\Plugin\Field\FieldType\TablefieldItem $item */
    foreach ($items as $index => $item) {
      if (empty($item->value)) {
        continue;
      }

      $header = [];
      $rows = [];
      /** @var array $table_data */
      $table_data = $item->value;

      // Extract caption.
      $caption = $table_data['caption'] ?? '';
      unset($table_data['caption']);

      // Prepare rows.
      /** @var array $row_data */
      foreach ($table_data as $row_key => $row_data) {
        $cells = [];
        /** @var string $cell */
        foreach ($row_data as $col_key => $cell) {
          if (!\is_numeric($col_key)) {
            continue;
          }

          $cells[$col_key] = [
            '#type' => 'component',
            '#component' => 'ui_suite_bootstrap:table_cell',
            '#slots' => [
              'content' => (empty($item->format) || !\is_string($item->format)) ? $cell : \check_markup($cell, $item->format),
            ],
          ];
        }

        $rows[$row_key] = [
          '#type' => 'component',
          '#component' => 'ui_suite_bootstrap:table_row',
          '#slots' => [
            'cells' => $cells,
          ],
        ];
      }

      if ($row_header) {
        // Pull the header for theming.
        $header_row = \array_shift($rows);
        if (\is_array($header_row)) {
          $header = $header_row['#slots']['cells'];

          foreach ($header as $key => $cell) {
            $header[$key]['#props']['tag'] = 'th';
          }
        }
      }
      if ($column_header) {
        foreach ($rows as $row_key => $row) {
          $rows[$row_key]['#slots']['cells'][0]['#props']['tag'] = 'th';
        }
      }

      $build[$index]['#slots'] = [
        'caption' => $caption,
        'header' => $header,
        'rows' => $rows,
      ];
    }

    return $build;
  }

}
