<?php namespace Wpstudio\Helpers\Classes\Observer;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Cache;

abstract class BaseObserver implements Observer
{
    protected static string $class;

    public static function clearCache(?Model $model = null, ?array $additionalPieces = []): void
    {
        Cache::tags(
            static::getCacheTag(
                !is_null($model) ? $model->getKey() : null,
                $additionalPieces,
                true
            )
        )->flush();
    }

    /**
     * @param int|Collection|array|null $identifiers
     * @param array|null $additionalPieces
     * @param bool $excludeBaseClassNameTagWithoutIdentifiers - это опция нужна, если вы хотите исключить имя базового класса обсервера из результирующего набора тегов
     * @desc $excludeBaseClassNameTagWithoutIdentifiers - выключает из результирующего массива тег кеша только с базовым классом, если переданы идентификаторы
     * @desc То есть в итоговой выборке - не будет тега, без идентификатора, если вообще идентификаторы переданы
     * @return array
     */
    public static function getCacheTag($identifiers = null, ?array $additionalPieces = [], bool $excludeBaseClassNameTagWithoutIdentifiers = false): array
    {
        return static::getCacheTagsWithMaybeIdentifiers(static::getClass(), $identifiers, $additionalPieces, $excludeBaseClassNameTagWithoutIdentifiers);
    }

    public static function formatCacheTag(array $pieces): string
    {
        return implode('.', $pieces);
    }

    /**
     * @param int|Collection|array|null $value
     * @return array
     */
    private static function forceArray($value = null): array
    {
        return $value instanceof Collection ? $value->toArray() : (array)$value;
    }

    /**
     * @param string $baseClassName
     * @param int|Collection|array|null $iterateIdentifiers
     * @param array|null $additionalTagPieces
     * @param bool $excludeBaseClassNameTagWithoutIdentifiers
     * @return array
     */
    private static function getCacheTagsWithMaybeIdentifiers(string $baseClassName, $iterateIdentifiers = [], ?array $additionalTagPieces = [], bool $excludeBaseClassNameTagWithoutIdentifiers = false): array
    {
        $iterateIdentifiers = static::forceArray($iterateIdentifiers);

        $cacheTags = [];

        if (!$excludeBaseClassNameTagWithoutIdentifiers || !$iterateIdentifiers) {
            $cacheTags = (array)static::formatCacheTag(array_merge([$baseClassName], $additionalTagPieces));
        }

        if ($iterateIdentifiers) {
            $cacheTags = array_merge(
                $cacheTags,
                array_map(
                    fn ($identifier) => static::formatCacheTag(
                        array_merge([$baseClassName, $identifier], $additionalTagPieces)
                    ),
                    $iterateIdentifiers
                )
            );
        }

        return $cacheTags;
    }
}