<?php

namespace App\Traits;

use Error;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;

trait HasCacheModel
{
    public function getCacheKey(): string
    {
        try {
            return constant(get_class($this) . '::' . 'CACHE_KEY');
        } catch (Error $e) {
            return $this->getTable();
        }
    }

    public static function getByCache(): Collection
    {
        $cache = Cache::get((new self)->getCacheKey());
        if (empty($cache)) {
            Cache::rememberForever((new self)->getCacheKey(), function () {
                return self::all();
            });
            $cache = Cache::get((new self)->getCacheKey());
        }
        return $cache;
    }

    public static function getActiveCache($field = 'is_active'): Collection
    {
        $cache = Cache::get((new self)->getCacheKey());
        if (empty($cache)) {
            Cache::rememberForever((new self)->getCacheKey(), function () {
                return self::all();
            });
            $cache = Cache::get((new self)->getCacheKey());
        }
        return $cache->where($field, 1);
    }

    public function newEloquentBuilder($query)
    {
        $cacheKey = $this->getCacheKey();

        return new class($query, $cacheKey) extends Builder
        {
            protected $cache_key;

            public function __construct($query, $cacheKey)
            {
                parent::__construct($query);
                $this->cache_key = $cacheKey;
            }

            public function delete()
            {
                Cache::delete($this->cache_key);
                return parent::delete();
            }

            public function create(array $attributes = [])
            {
                Cache::delete($this->cache_key);
                return parent::create($attributes);
            }

            public function update(array $values)
            {
                Cache::delete($this->cache_key);
                return parent::update($values);
            }

            public function updateOrCreate(array $attributes, array | null $values = [])
            {
                Cache::delete($this->cache_key);
                return parent::updateOrCreate($attributes, $values);
            }
        };
    }

    public static function destroy(...$args)
    {
        Cache::delete((new self)->getCacheKey());
        return parent::destroy(...$args);
    }

    public function update(...$args)
    {
        Cache::delete((new self)->getCacheKey());
        return parent::update(...$args);
    }
}
