<?php

declare(strict_types=1);

namespace Drupal\simple_interactive_maps\Entity;

use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\Attribute\ConfigEntityType;
use Drupal\Core\Entity\EntityDeleteForm;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\simple_interactive_maps\Form\InteractiveMapForm;
use Drupal\simple_interactive_maps\InteractiveMapInterface;
use Drupal\simple_interactive_maps\InteractiveMapListBuilder;

/**
 * Defines the interactive map entity type.
 */
#[ConfigEntityType(
  id: 'interactive_map',
  label: new TranslatableMarkup('Interactive Map'),
  label_collection: new TranslatableMarkup('Interactive Maps'),
  label_singular: new TranslatableMarkup('interactive map'),
  label_plural: new TranslatableMarkup('interactive maps'),
  label_count: [
    'singular' => '@count interactive map',
    'plural' => '@count interactive maps',
  ],
  handlers: [
    'list_builder' => InteractiveMapListBuilder::class,
    'form' => [
      'add' => InteractiveMapForm::class,
      'edit' => InteractiveMapForm::class,
      'delete' => EntityDeleteForm::class,
    ],
  ],
  config_prefix: 'interactive_map',
  admin_permission: 'administer interactive_map',
  links: [
    'collection' => '/admin/structure/interactive-map',
    'add-form' => '/admin/structure/interactive-map/add',
    'edit-form' => '/admin/structure/interactive-map/{interactive_map}',
    'delete-form' => '/admin/structure/interactive-map/{interactive_map}/delete',
  ],
  entity_keys: [
    'id' => 'id',
    'label' => 'label',
    'uuid' => 'uuid',
  ],
  config_export: [
    'id',
    'label',
    'base_map',
    'description',
    'fill_color',
    'hover_color',
    'stroke_color',
    'regions',
    'groups',
  ],
)]
class InteractiveMap extends ConfigEntityBase implements InteractiveMapInterface {

  /**
   * The example ID.
   */
  protected string $id;

  /**
   * The example label.
   */
  protected string $label;

  /**
   * ID of the map_definition plugin for this map.
   */
  protected string $base_map;

  /**
   * The example description.
   */
  protected array $description = ['value' => '', 'format' => 'full_html'];

  /**
   * The fill color.
   */
  protected string $fillColor = '#4ba0a6';

  /**
   * The hover color.
   */
  protected string $hoverColor = '#076369';

  /**
   * The stroke color.
   */
  protected string $strokeColor = '#e6e6e6';

  /**
   * The region details.
   */
  protected array $regions = [];

  /**
   * The group data.
   */
  protected array $groups = [];

  /**
   * Given a group id, removes it from the map configuration.
   *
   * @param string $group
   *   Group id.
   */
  public function deleteGroup(string $group): void {
    unset($this->groups[$group]);
  }

  /**
   * {@inheritDoc}
   */
  public function compareGroupsData(array $groups): bool {
    $mapGroups = $this->groups;

    // If the groups arrays are the same, return true.
    if ($groups === $mapGroups) {
      return TRUE;
    }

    return $this->compareArrayRecursive($groups, $mapGroups);
  }

  /**
   * {@inheritDoc}
   */
  public function getEmbedCode(): string {
    return \sprintf('[interactive_map map=%s]', $this->id);
  }

  /**
   * {@inheritDoc}
   */
  public function getRegions(): array {
    return $this->regions;
  }

  /**
   * {@inheritDoc}
   */
  public function setRegions(array $regions): void {
    $this->regions = $regions;
  }

  /**
   * {@inheritDoc}
   */
  public function getGroups(): array {
    return $this->groups;
  }

  /**
   * {@inheritDoc}
   */
  public function setGroups(array $groups): void {
    $this->groups = $groups;
  }

  /**
   * Recursively compare two arrays.
   *
   * @param array $array1
   *   First array.
   * @param array $array2
   *   Second array.
   *
   * @return bool
   *   TRUE if the arrays are the same, FALSE otherwise.
   */
  private function compareArrayRecursive(array $array1, array $array2): bool {
    if (\count($array1) !== \count($array2)) {
      return FALSE;
    }

    foreach ($array1 as $key => $value) {
      if (!\array_key_exists($key, $array2)) {
        return FALSE;
      }

      if (\is_array($value)) {
        if (!$this->compareArrayRecursive($value, $array2[$key])) {
          return FALSE;
        }
      }
      elseif ($value !== $array2[$key]) {
        return FALSE;
      }
    }

    return TRUE;
  }

}
