<?php

namespace App\Helpers;

use Illuminate\Support\Facades\Cache;

class CacheHelper
{
    /**
     * Get cache TTL from config
     *
     * @param string $key
     * @return int
     */
    public static function ttl(string $key): int
    {
        return config("performance.cache.ttl.{$key}", 3600);
    }

    /**
     * Remember with tags (Redis only)
     *
     * @param string $cacheKey
     * @param array $tags
     * @param int $ttl
     * @param callable $callback
     * @return mixed
     */
    public static function rememberWithTags(string $cacheKey, array $tags, int $ttl, callable $callback)
    {
        if (config('cache.default') === 'redis') {
            return Cache::tags($tags)->remember($cacheKey, $ttl, $callback);
        }

        // Fallback to regular cache if not using Redis
        return Cache::remember($cacheKey, $ttl, $callback);
    }

    /**
     * Flush cache by tags (Redis only)
     *
     * @param array $tags
     * @return void
     */
    public static function flushTags(array $tags): void
    {
        if (config('cache.default') === 'redis') {
            Cache::tags($tags)->flush();
        }
    }

    /**
     * Cache locations with proper TTL
     *
     * @return \Illuminate\Support\Collection
     */
    public static function locations()
    {
        return Cache::remember(
            'locations.all',
            self::ttl('locations'),
            fn() => \App\Models\Location::withCount('listings')->orderBy('name')->get()
        );
    }

    /**
     * Cache rental types with proper TTL
     *
     * @return \Illuminate\Support\Collection
     */
    public static function rentalTypes()
    {
        return Cache::remember(
            'rental_types.all',
            self::ttl('rental_types'),
            fn() => \App\Models\RentalType::all()
        );
    }

    /**
     * Cache featured listings
     *
     * @param int $limit
     * @return \Illuminate\Support\Collection
     */
    public static function featuredListings(int $limit = 20)
    {
        return Cache::remember(
            "listings.featured.{$limit}",
            self::ttl('featured_listings'),
            function () use ($limit) {
                return \App\Models\Listing::with(['location', 'rentalType'])
                    ->withCount('reviews')
                    ->withAvg('reviews', 'rating')
                    ->where('is_featured', true)
                    ->where('is_available', true)
                    ->limit($limit)
                    ->get();
            }
        );
    }

    /**
     * Cache settings value
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public static function setting(string $key, $default = null)
    {
        return Cache::remember(
            "setting.{$key}",
            self::ttl('settings'),
            fn() => \App\Models\Setting::get($key, $default)
        );
    }

    /**
     * Cache pickup locations
     *
     * @return \Illuminate\Support\Collection
     */
    public static function pickupLocations()
    {
        return Cache::remember(
            'pickup_locations.active',
            self::ttl('pickup_locations'),
            fn() => \App\Models\PickupLocation::where('is_active', true)->get()
        );
    }

    /**
     * Cache amenities
     *
     * @return \Illuminate\Support\Collection
     */
    public static function amenities()
    {
        return Cache::remember(
            'amenities.all',
            self::ttl('amenities'),
            fn() => \App\Models\Amenity::where('is_active', true)->orderBy('name')->get()
        );
    }

    /**
     * Clear all application caches
     *
     * @return void
     */
    public static function clearAll(): void
    {
        Cache::flush();

        // Clear specific caches
        \Illuminate\Support\Facades\Artisan::call('cache:clear');
        \Illuminate\Support\Facades\Artisan::call('config:clear');
        \Illuminate\Support\Facades\Artisan::call('route:clear');
        \Illuminate\Support\Facades\Artisan::call('view:clear');
    }

    /**
     * Clear specific model cache
     *
     * @param string $model
     * @return void
     */
    public static function clearModel(string $model): void
    {
        $cacheKeys = [
            'location' => ['locations.all', 'locations.*'],
            'rental_type' => ['rental_types.all'],
            'listing' => ['listings.*', 'listings.featured.*'],
            'setting' => ['setting.*'],
            'amenity' => ['amenities.all'],
            'pickup_location' => ['pickup_locations.active'],
        ];

        if (isset($cacheKeys[$model])) {
            foreach ($cacheKeys[$model] as $pattern) {
                if (strpos($pattern, '*') !== false) {
                    // Flush pattern-based keys (requires Redis)
                    self::flushPattern($pattern);
                } else {
                    Cache::forget($pattern);
                }
            }
        }
    }

    /**
     * Flush cache keys by pattern (Redis only)
     *
     * @param string $pattern
     * @return void
     */
    protected static function flushPattern(string $pattern): void
    {
        if (config('cache.default') === 'redis') {
            $redis = Cache::getStore()->connection();
            $keys = $redis->keys(config('cache.prefix') . ':' . $pattern);

            foreach ($keys as $key) {
                $redis->del($key);
            }
        }
    }

    /**
     * Get cache statistics (development only)
     *
     * @return array
     */
    public static function stats(): array
    {
        if (config('app.debug')) {
            return [
                'driver' => config('cache.default'),
                'redis_connected' => self::isRedisConnected(),
                'cache_size' => self::estimateCacheSize(),
            ];
        }

        return [];
    }

    /**
     * Check if Redis is connected
     *
     * @return bool
     */
    protected static function isRedisConnected(): bool
    {
        if (config('cache.default') !== 'redis') {
            return false;
        }

        try {
            Cache::getStore()->connection()->ping();
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * Estimate cache size (approximate)
     *
     * @return string
     */
    protected static function estimateCacheSize(): string
    {
        try {
            if (config('cache.default') === 'redis') {
                $redis = Cache::getStore()->connection();
                $info = $redis->info('memory');
                return $info['used_memory_human'] ?? 'Unknown';
            }
        } catch (\Exception $e) {
            //
        }

        return 'N/A';
    }
}
