<?php

namespace App\Services\Cache;

use Illuminate\Support\Facades\Cache;
use Closure;

/**
 * Cache Service
 *
 * Provides a centralized caching layer with standardized
 * cache key management and common caching operations.
 */
class CacheService
{
    /**
     * Default cache TTL in seconds (1 hour)
     */
    protected int $defaultTtl = 3600;

    /**
     * Short cache TTL (5 minutes)
     */
    protected int $shortTtl = 300;

    /**
     * Long cache TTL (24 hours)
     */
    protected int $longTtl = 86400;

    /**
     * Cache key prefixes by module
     */
    protected array $prefixes = [
        'customer' => 'customer_vendor',
        'rfq' => 'rfq',
        'quotation' => 'quotation',
        'sales_order' => 'sales_order',
        'invoice' => 'invoice',
        'purchase_order' => 'purchase_order',
        'grn' => 'grn',
        'route_card' => 'route_card',
        'employee' => 'employee',
        'raw_material' => 'raw_material',
        'stock_item' => 'stock_item',
        'machine' => 'machine',
        'process' => 'process',
        'dashboard' => 'dashboard',
        'report' => 'report',
    ];

    /**
     * Get or set a cached value
     */
    public function remember(string $key, Closure $callback, ?int $ttl = null): mixed
    {
        return Cache::remember($key, $ttl ?? $this->defaultTtl, $callback);
    }

    /**
     * Get or set a cached value forever
     */
    public function rememberForever(string $key, Closure $callback): mixed
    {
        return Cache::rememberForever($key, $callback);
    }

    /**
     * Store a value in cache
     */
    public function put(string $key, mixed $value, ?int $ttl = null): bool
    {
        return Cache::put($key, $value, $ttl ?? $this->defaultTtl);
    }

    /**
     * Get a value from cache
     */
    public function get(string $key, mixed $default = null): mixed
    {
        return Cache::get($key, $default);
    }

    /**
     * Check if cache key exists
     */
    public function has(string $key): bool
    {
        return Cache::has($key);
    }

    /**
     * Remove a cached value
     */
    public function forget(string $key): bool
    {
        return Cache::forget($key);
    }

    /**
     * Clear all cache for a specific module
     */
    public function clearModule(string $module): void
    {
        $prefix = $this->prefixes[$module] ?? $module;
        Cache::tags([$prefix])->flush();
    }

    /**
     * Clear all application cache
     */
    public function clearAll(): void
    {
        Cache::flush();
    }

    // ──────────────────────────────────────────────────────────────────────────
    // CACHE KEY GENERATORS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate cache key for a single record
     */
    public function keyForRecord(string $module, int $id): string
    {
        $prefix = $this->prefixes[$module] ?? $module;
        return "{$prefix}:{$id}";
    }

    /**
     * Generate cache key for a list
     */
    public function keyForList(string $module, array $filters = []): string
    {
        $prefix = $this->prefixes[$module] ?? $module;
        $filterHash = md5(json_encode($filters));
        return "{$prefix}:list:{$filterHash}";
    }

    /**
     * Generate cache key for counts
     */
    public function keyForCount(string $module, ?string $scope = null): string
    {
        $prefix = $this->prefixes[$module] ?? $module;
        $suffix = $scope ? ":{$scope}" : '';
        return "{$prefix}:count{$suffix}";
    }

    /**
     * Generate cache key for dashboard data
     */
    public function keyForDashboard(string $role, ?string $section = null): string
    {
        $suffix = $section ? ":{$section}" : '';
        return "dashboard:{$role}{$suffix}";
    }

    /**
     * Generate cache key for report
     */
    public function keyForReport(string $reportType, array $params = []): string
    {
        $paramHash = md5(json_encode($params));
        return "report:{$reportType}:{$paramHash}";
    }

    // ──────────────────────────────────────────────────────────────────────────
    // MODULE-SPECIFIC CACHING METHODS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Cache customer/vendor list
     */
    public function cacheCustomers(Closure $callback): mixed
    {
        return $this->remember(
            $this->keyForList('customer', ['role' => 'Customer']),
            $callback,
            $this->longTtl
        );
    }

    /**
     * Cache vendor list
     */
    public function cacheVendors(Closure $callback): mixed
    {
        return $this->remember(
            $this->keyForList('customer', ['role' => 'Vendor']),
            $callback,
            $this->longTtl
        );
    }

    /**
     * Cache master data (long TTL)
     */
    public function cacheMasterData(string $type, Closure $callback): mixed
    {
        return $this->remember(
            "master_data:{$type}",
            $callback,
            $this->longTtl
        );
    }

    /**
     * Cache dashboard statistics
     */
    public function cacheDashboardStats(string $role, Closure $callback): mixed
    {
        return $this->remember(
            $this->keyForDashboard($role, 'stats'),
            $callback,
            $this->shortTtl
        );
    }

    /**
     * Cache active processes count
     */
    public function cacheActiveProcesses(Closure $callback): mixed
    {
        return $this->remember(
            $this->keyForCount('route_card', 'active_processes'),
            $callback,
            $this->shortTtl
        );
    }

    // ──────────────────────────────────────────────────────────────────────────
    // CACHE INVALIDATION METHODS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Invalidate customer cache
     */
    public function invalidateCustomer(int $id): void
    {
        $this->forget($this->keyForRecord('customer', $id));
        $this->forget($this->keyForList('customer', ['role' => 'Customer']));
        $this->forget($this->keyForList('customer', ['role' => 'Vendor']));
        $this->forget($this->keyForList('customer', ['role' => 'Both']));
    }

    /**
     * Invalidate sales order cache
     */
    public function invalidateSalesOrder(int $id): void
    {
        $this->forget($this->keyForRecord('sales_order', $id));
        $this->invalidateDashboardCache();
    }

    /**
     * Invalidate invoice cache
     */
    public function invalidateInvoice(int $id): void
    {
        $this->forget($this->keyForRecord('invoice', $id));
        $this->invalidateDashboardCache();
    }

    /**
     * Invalidate route card cache
     */
    public function invalidateRouteCard(int $id): void
    {
        $this->forget($this->keyForRecord('route_card', $id));
        $this->forget($this->keyForCount('route_card', 'active_processes'));
        $this->invalidateDashboardCache();
    }

    /**
     * Invalidate all dashboard caches
     */
    public function invalidateDashboardCache(): void
    {
        foreach (['admin', 'manager', 'superadmin'] as $role) {
            $this->forget($this->keyForDashboard($role, 'stats'));
            $this->forget($this->keyForDashboard($role, 'charts'));
        }
    }

    // ──────────────────────────────────────────────────────────────────────────
    // TTL GETTERS
    // ──────────────────────────────────────────────────────────────────────────

    public function getShortTtl(): int
    {
        return $this->shortTtl;
    }

    public function getDefaultTtl(): int
    {
        return $this->defaultTtl;
    }

    public function getLongTtl(): int
    {
        return $this->longTtl;
    }
}
