<?php
/**
 * Cache Manager
 *
 * Centralized caching system for repository operations
 *
 * @package NemtlyBooking
 * @since   PBOOKING_SINCE
 */

namespace NemtlyBooking\Core;

/**
 * Cache Manager class
 *
 * @since PBOOKING_SINCE
 */
class Cache_Manager {

    /**
     * Cache prefix
     *
     * @var string
     */
    const CACHE_PREFIX = 'nemtly_booking_';

    /**
     * Default cache expiration (1 hour)
     *
     * @var int
     */
    const DEFAULT_EXPIRATION = 3600;

    /**
     * Cache group for events
     *
     * @var string
     */
    const EVENTS_GROUP = 'events';

    /**
     * Cache group for bookings
     *
     * @var string
     */
    const BOOKINGS_GROUP = 'bookings';

    /**
     * Cache group for users
     *
     * @var string
     */
    const USERS_GROUP = 'users';

    /**
     * Cache group for statistics
     *
     * @var string
     */
    const STATS_GROUP = 'statistics';

    /**
     * Get cache key
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key   Cache key.
     * @param string $group Cache group.
     *
     * @return string Full cache key.
     */
    public static function get_cache_key( $key, $group = '' ) {
        $prefix = self::CACHE_PREFIX;
        if ( $group ) {
            $prefix .= $group . '_';
        }
        return $prefix . $key;
    }

    /**
     * Get cached data
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key Cache key.
     * @param string $group Cache group.
     *
     * @return mixed|false Cached data or false if not found.
     */
    public static function get( $key, $group = '' ) {
        $cache_key = self::get_cache_key( $key, $group );
        return wp_cache_get( $cache_key, $group ? $group : 'default' );
    }

    /**
     * Set cached data
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key        Cache key.
     * @param mixed  $data       Data to cache.
     * @param int    $expiration Cache expiration in seconds.
     * @param string $group      Cache group.
     *
     * @return bool True on success, false on failure.
     */
    public static function set( $key, $data, $expiration = null, $group = '' ) {
        if ( null === $expiration ) {
            $expiration = self::DEFAULT_EXPIRATION;
        }

        $cache_key = self::get_cache_key( $key, $group );
        return wp_cache_set( $cache_key, $data, $group ? $group : 'default', $expiration );
    }

    /**
     * Delete cached data
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key   Cache key.
     * @param string $group Cache group.
     *
     * @return bool True on success, false on failure.
     */
    public static function delete( $key, $group = '' ) {
        $cache_key = self::get_cache_key( $key, $group );
        return wp_cache_delete( $cache_key, $group ? $group : 'default' );
    }

    /**
     * Clear all cache for a group
     *
     * @since PBOOKING_SINCE
     *
     * @param string $group Cache group.
     *
     * @return bool True on success, false on failure.
     */
    public static function clear_group( $group ) {
        return wp_cache_flush_group( $group );
    }

    /**
     * Clear all plugin cache
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True on success, false on failure.
     */
    public static function clear_all() {
        $groups = [ self::EVENTS_GROUP, self::BOOKINGS_GROUP, self::USERS_GROUP, self::STATS_GROUP ];

        foreach ( $groups as $group ) {
            self::clear_group( $group );
        }

        return true;
    }

    /**
     * Get or set cache with callback
     *
     * @since PBOOKING_SINCE
     *
     * @param string   $key        Cache key.
     * @param callable $callback   Callback to generate data if not cached.
     * @param int      $expiration Cache expiration in seconds.
     * @param string   $group      Cache group.
     *
     * @return mixed Cached or generated data.
     */
    public static function remember( $key, $callback, $expiration = null, $group = '' ) {
        $cached = self::get( $key, $group );

        if ( false !== $cached ) {
            return $cached;
        }

        $data = call_user_func( $callback );
        self::set( $key, $data, $expiration, $group );

        return $data;
    }

    /**
     * Invalidate cache for an event
     *
     * @since PBOOKING_SINCE
     *
     * @param int $event_id Event ID.
     */
    public static function invalidate_event_cache( $event_id ) {
        // Clear event-specific cache
        self::delete( "event_{$event_id}", self::EVENTS_GROUP );

        // Clear related caches
        self::delete( 'events_list', self::EVENTS_GROUP );
        self::delete( 'upcoming_events', self::EVENTS_GROUP );
        self::delete( 'events_statistics', self::STATS_GROUP );

        // Clear booking caches that might be affected
        self::delete( "bookings_event_{$event_id}", self::BOOKINGS_GROUP );
        self::delete( 'bookings_statistics', self::STATS_GROUP );
    }

    /**
     * Invalidate cache for a booking
     *
     * @since PBOOKING_SINCE
     *
     * @param int $booking_id Booking ID.
     * @param int $event_id   Event ID.
     */
    public static function invalidate_booking_cache( $booking_id, $event_id = null ) {
        // Clear booking-specific cache
        self::delete( "booking_{$booking_id}", self::BOOKINGS_GROUP );

        // Clear related caches
        self::delete( 'bookings_list', self::BOOKINGS_GROUP );
        self::delete( 'bookings_statistics', self::STATS_GROUP );

        // Clear event cache if event ID provided
        if ( $event_id ) {
            self::invalidate_event_cache( $event_id );
        }
    }

    /**
     * Invalidate cache for a user
     *
     * @since PBOOKING_SINCE
     *
     * @param int $user_id User ID.
     */
    public static function invalidate_user_cache( $user_id ) {
        // Clear user-specific cache
        self::delete( "user_{$user_id}", self::USERS_GROUP );
        self::delete( "bookings_user_{$user_id}", self::BOOKINGS_GROUP );
    }

    /**
     * Get cache statistics
     *
     * @since PBOOKING_SINCE
     *
     * @return array Cache statistics.
     */
    public static function get_cache_stats() {
        global $wp_object_cache;

        if ( ! $wp_object_cache ) {
            return [];
        }

        return [
            'cache_hits'   => $wp_object_cache->cache_hits ?? 0,
            'cache_misses' => $wp_object_cache->cache_misses ?? 0,
            'cache_ratio'  => $wp_object_cache->cache_hits / ( $wp_object_cache->cache_hits + $wp_object_cache->cache_misses ) ?? 0,
        ];
    }

    /**
     * Check if caching is available
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True if caching is available, false otherwise.
     */
    public static function is_available() {
        return function_exists( 'wp_cache_get' );
    }

    /**
     * Get cache configuration
     *
     * @since PBOOKING_SINCE
     *
     * @return array Cache configuration.
     */
    public static function get_config() {
        return [
            'enabled'            => self::is_available(),
            'default_expiration' => self::DEFAULT_EXPIRATION,
            'groups'             => [
                self::EVENTS_GROUP,
                self::BOOKINGS_GROUP,
                self::USERS_GROUP,
                self::STATS_GROUP,
            ],
        ];
    }
}
