<?php

namespace App\Models\Traits;

use App\Services\Cache\CacheService;
use Illuminate\Support\Facades\Cache;

/**
 * Has Cache Trait
 *
 * Provides caching capabilities for Eloquent models
 * with automatic cache invalidation on model events.
 */
trait HasCache
{
    /**
     * Boot the trait
     */
    public static function bootHasCache(): void
    {
        // Invalidate cache when model is saved
        static::saved(function ($model) {
            $model->invalidateModelCache();
        });

        // Invalidate cache when model is deleted
        static::deleted(function ($model) {
            $model->invalidateModelCache();
        });
    }

    /**
     * Get cache key for this model
     */
    public function getCacheKey(): string
    {
        return $this->getCachePrefix() . ':' . $this->getKey();
    }

    /**
     * Get cache prefix for this model type
     */
    protected function getCachePrefix(): string
    {
        return property_exists($this, 'cachePrefix')
            ? $this->cachePrefix
            : strtolower(class_basename(static::class));
    }

    /**
     * Get cache TTL for this model
     */
    protected function getCacheTtl(): int
    {
        return property_exists($this, 'cacheTtl')
            ? $this->cacheTtl
            : 3600; // 1 hour default
    }

    /**
     * Get cached model by ID
     */
    public static function findCached(int $id): ?static
    {
        $instance = new static;
        $key = $instance->getCachePrefix() . ':' . $id;

        return Cache::remember($key, $instance->getCacheTtl(), function () use ($id) {
            return static::find($id);
        });
    }

    /**
     * Get cached model with relationships
     */
    public static function findCachedWith(int $id, array $relations): ?static
    {
        $instance = new static;
        $relationsKey = md5(json_encode($relations));
        $key = $instance->getCachePrefix() . ':' . $id . ':with:' . $relationsKey;

        return Cache::remember($key, $instance->getCacheTtl(), function () use ($id, $relations) {
            return static::with($relations)->find($id);
        });
    }

    /**
     * Cache this model instance
     */
    public function cache(): static
    {
        Cache::put($this->getCacheKey(), $this, $this->getCacheTtl());
        return $this;
    }

    /**
     * Invalidate cache for this model
     */
    public function invalidateModelCache(): void
    {
        Cache::forget($this->getCacheKey());

        // Also invalidate list caches
        $this->invalidateListCaches();
    }

    /**
     * Invalidate list caches (override in model if needed)
     */
    protected function invalidateListCaches(): void
    {
        // Override in model to clear specific list caches
        // Example: Cache::forget('customers:list:active');
    }

    /**
     * Get all cached models of this type
     */
    public static function allCached(): \Illuminate\Support\Collection
    {
        $instance = new static;
        $key = $instance->getCachePrefix() . ':all';

        return Cache::remember($key, $instance->getCacheTtl(), function () {
            return static::all();
        });
    }

    /**
     * Clear all cache for this model type
     */
    public static function clearModelCache(): void
    {
        $instance = new static;
        $prefix = $instance->getCachePrefix();

        // Clear the 'all' cache
        Cache::forget($prefix . ':all');

        // If using cache tags (Redis), flush the tag
        if (method_exists(Cache::getStore(), 'tags')) {
            Cache::tags([$prefix])->flush();
        }
    }
}
