<?php

namespace Drupal\address_tr\EventSubscriber;

use Drupal\address\Event\AddressEvents;
use Drupal\address\Event\AddressFormatEvent;
use Drupal\address\Event\SubdivisionsEvent;
use Drupal\address_tr\Service\SubdivisionLoaderService;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use CommerceGuys\Addressing\AddressFormat\AdministrativeAreaType;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Replaces format and subdivisions info for TR addresses.
 *
 * @package Drupal\address_tr\EventSubscriber
 */
class AddressEventsSubscriber implements EventSubscriberInterface
{

    use StringTranslationTrait;

    /**
     * The subdivision loader service.
     *
     * @var \Drupal\address_tr\Service\SubdivisionLoaderService
     */
    protected $subdivisionLoader;

    /**
     * The cache backend service.
     *
     * @var \Drupal\Core\Cache\CacheBackendInterface
     */
    protected $cache;

    /**
     * Constructs an AddressEventsSubscriber object.
     *
     * @param \Drupal\address_tr\Service\SubdivisionLoaderService $subdivision_loader
     *   The subdivision loader service.
     * @param \Drupal\Core\Cache\CacheBackendInterface $cache
     *   The cache backend.
     */
    public function __construct(SubdivisionLoaderService $subdivision_loader, CacheBackendInterface $cache)
    {
        $this->subdivisionLoader = $subdivision_loader;
        $this->cache = $cache;
    }

    /**
     * {@inheritdoc}
     *
     * @return array
     *   The event names to listen to.
     */
    public static function getSubscribedEvents()
    {
        return [
            AddressEvents::ADDRESS_FORMAT => ['onAddressFormat'],
            AddressEvents::SUBDIVISIONS => ['onSubdivisions'],
        ];
    }

    /**
     * Alters the address format for Turkey.
     *
     * @param \Drupal\address\Event\AddressFormatEvent $event
     *   The address format event.
     */
    public function onAddressFormat(AddressFormatEvent $event)
    {
        $definition = $event->getDefinition();

        if (isset($definition['country_code']) && $definition['country_code'] == 'TR') {
            $definition['format'] = "%givenName %familyName\n%organization\n%administrativeArea / %locality / %dependentLocality\n%addressLine1";
            $definition['subdivision_depth'] = 3;
            $definition['administrative_area_type'] = AdministrativeAreaType::PROVINCE;

            // Make postal code optional for Turkish addresses.
            if (!isset($definition['required_fields'])) {
                $definition['required_fields'] = [];
            }
            // Remove postal_code from required fields if it exists.
            $key = array_search('postal_code', $definition['required_fields']);
            if ($key !== FALSE) {
                unset($definition['required_fields'][$key]);
            }

            $event->setDefinition($definition);
        }
    }

    /**
     * Replaces default subdivisions list for Turkey.
     *
     * @param \Drupal\address\Event\SubdivisionsEvent $event
     *   The subdivisions event.
     */
    public function onSubdivisions(SubdivisionsEvent $event)
    {
        $parents = $event->getParents();
        if (empty($parents)) {
            return;
        }

        $country_code = $parents[0];

        if ($country_code != 'TR') {
            return;
        }

        $cache_key = 'address.subdivisions.' . implode('_', $parents);
        $definitions = NULL;

        // Try to load from cache first.
        if ($cached = $this->cache->get($cache_key)) {
            $definitions = $cached->data;
        } else {
            // Load subdivision data using the subdivision loader service.
            $definitions = $this->subdivisionLoader->loadSubdivisions($parents);

            // Cache the loaded data if found.
            if ($definitions !== NULL) {
                $this->cache->set($cache_key, $definitions, CacheBackendInterface::CACHE_PERMANENT, ['subdivisions']);
            }
        }

        // Always set definitions, even if empty.
        if ($definitions === NULL) {
            $definitions = ['subdivisions' => []];
        }
        $event->setDefinitions($definitions);
    }
}
