<?php
namespace PrimeLink\Helpers;

if ( ! defined( 'ABSPATH' ) ) { exit; }

/**
 * Cache helper using Symfony Cache if available, with fallback to WooCommerce transients.
 */
final class CacheHelper {

    /**
     * Cache adapter instance (Symfony Cache or null).
     *
     * @var object|null
     */
    private static $cache_adapter = null;

    /**
     * Default TTL in seconds (1 hour).
     */
    const DEFAULT_TTL = 3600;

    /**
     * Get cache adapter (Symfony Cache or null for WooCommerce fallback).
     *
     * @return object|null
     */
    private static function get_cache_adapter() {
        if ( self::$cache_adapter !== null ) {
            return self::$cache_adapter;
        }

        // Symfony Cache 6.x requires PHP 8.1+
        // If PHP < 8.1, use WooCommerce transients fallback directly
        if ( version_compare( PHP_VERSION, '8.1.0', '<' ) ) {
            self::$cache_adapter = false;
            return false;
        }

        // Try prefixed Symfony Cache first (production), then normal (development)
        $filesystem_adapter_class = null;
        $cache_class = null;

        if ( class_exists( '\PrimeLink\Vendor\Symfony\Component\Cache\Adapter\FilesystemAdapter' ) ) {
            $filesystem_adapter_class = '\PrimeLink\Vendor\Symfony\Component\Cache\Adapter\FilesystemAdapter';
            $cache_class = '\PrimeLink\Vendor\Symfony\Component\Cache\Cache';
        } elseif ( class_exists( '\Symfony\Component\Cache\Adapter\FilesystemAdapter' ) ) {
            $filesystem_adapter_class = '\Symfony\Component\Cache\Adapter\FilesystemAdapter';
            $cache_class = '\Symfony\Component\Cache\Cache';
        }

        if ( $filesystem_adapter_class ) {
            try {
                // Create cache directory in uploads/primelink/cache
                $upload_dir = wp_upload_dir();
                $cache_dir = trailingslashit( $upload_dir['basedir'] ) . 'primelink/cache/';
                
                if ( ! file_exists( $cache_dir ) ) {
                    wp_mkdir_p( $cache_dir );
                }

                // Create FilesystemAdapter with namespace and default TTL
                // Parameters: namespace, defaultLifetime, directory
                self::$cache_adapter = new $filesystem_adapter_class( 'primelink', self::DEFAULT_TTL, $cache_dir );
            } catch ( \Exception $e ) {
                // Fallback to WooCommerce transients
                LoggerHelper::warning( 'Symfony Cache initialization failed, using WooCommerce transients', array(
                    'error' => $e->getMessage(),
                ) );
                self::$cache_adapter = false;
            }
        } else {
            self::$cache_adapter = false;
        }

        return self::$cache_adapter;
    }

    /**
     * Check if Symfony Cache is available.
     *
     * @return bool
     */
    public static function has_symfony_cache() {
        $adapter = self::get_cache_adapter();
        return $adapter !== false && $adapter !== null;
    }

    /**
     * Get cached value.
     *
     * @param string $key Cache key.
     * @param mixed  $default Default value if not found.
     * @return mixed Cached value or default.
     */
    public static function get( $key, $default = null ) {
        $key = self::normalize_key( $key );

        if ( self::has_symfony_cache() ) {
            try {
                $adapter = self::get_cache_adapter();
                $item = $adapter->getItem( $key );
                
                if ( $item->isHit() ) {
                    $value = $item->get();
                    // Handle serialized data
                    if ( is_string( $value ) && ( $unserialized = @unserialize( $value ) ) !== false ) {
                        return $unserialized;
                    }
                    return $value;
                }
            } catch ( \Exception $e ) {
                LoggerHelper::warning( 'Cache get failed, falling back to WooCommerce', array(
                    'key'   => $key,
                    'error' => $e->getMessage(),
                ) );
            }
        }

        // Fallback to WooCommerce transients
        $value = get_transient( $key );
        return $value !== false ? $value : $default;
    }

    /**
     * Set cached value.
     *
     * @param string $key Cache key.
     * @param mixed  $value Value to cache.
     * @param int    $ttl Time to live in seconds (0 = use default).
     * @return bool True on success.
     */
    public static function set( $key, $value, $ttl = 0 ) {
        $key = self::normalize_key( $key );
        
        if ( $ttl <= 0 ) {
            $ttl = self::DEFAULT_TTL;
        }

        if ( self::has_symfony_cache() ) {
            try {
                $adapter = self::get_cache_adapter();
                $item = $adapter->getItem( $key );
                
                // Serialize complex data types
                $cache_value = is_scalar( $value ) ? $value : serialize( $value );
                $item->set( $cache_value );
                $item->expiresAfter( $ttl );
                
                return $adapter->save( $item );
            } catch ( \Exception $e ) {
                LoggerHelper::warning( 'Cache set failed, falling back to WooCommerce', array(
                    'key'   => $key,
                    'error' => $e->getMessage(),
                ) );
            }
        }

        // Fallback to WooCommerce transients
        return set_transient( $key, $value, $ttl );
    }

    /**
     * Delete cached value.
     *
     * @param string $key Cache key.
     * @return bool True on success.
     */
    public static function delete( $key ) {
        $key = self::normalize_key( $key );

        if ( self::has_symfony_cache() ) {
            try {
                $adapter = self::get_cache_adapter();
                return $adapter->deleteItem( $key );
            } catch ( \Exception $e ) {
                LoggerHelper::warning( 'Cache delete failed, falling back to WooCommerce', array(
                    'key'   => $key,
                    'error' => $e->getMessage(),
                ) );
            }
        }

        // Fallback to WooCommerce transients
        return delete_transient( $key );
    }

    /**
     * Clear all cache (or cache with specific prefix).
     *
     * @param string $prefix Optional prefix to clear only matching keys.
     * @return bool True on success.
     */
    public static function clear( $prefix = '' ) {
        if ( self::has_symfony_cache() ) {
            try {
                $adapter = self::get_cache_adapter();
                
                if ( empty( $prefix ) ) {
                    // Clear all cache
                    return $adapter->clear();
                } else {
                    // Clear only items with prefix
                    // Symfony Cache doesn't have built-in prefix clearing, so we'll use a workaround
                    // For now, just clear all (can be improved later)
                    return $adapter->clear();
                }
            } catch ( \Exception $e ) {
                LoggerHelper::warning( 'Cache clear failed', array(
                    'prefix' => $prefix,
                    'error'  => $e->getMessage(),
                ) );
            }
        }

        // For WooCommerce transients, we can't easily clear all, so return true
        // Individual keys should be deleted explicitly
        return true;
    }

    /**
     * Check if a key exists in cache.
     *
     * @param string $key Cache key.
     * @return bool True if exists.
     */
    public static function has( $key ) {
        $key = self::normalize_key( $key );

        if ( self::has_symfony_cache() ) {
            try {
                $adapter = self::get_cache_adapter();
                return $adapter->hasItem( $key );
            } catch ( \Exception $e ) {
                LoggerHelper::warning( 'Cache has check failed, falling back to WooCommerce', array(
                    'key'   => $key,
                    'error' => $e->getMessage(),
                ) );
            }
        }

        // Fallback to WooCommerce transients
        return get_transient( $key ) !== false;
    }

    /**
     * Get or set cached value (cache-aside pattern).
     *
     * @param string   $key Cache key.
     * @param callable $callback Callback to generate value if not cached.
     * @param int      $ttl Time to live in seconds (0 = use default).
     * @return mixed Cached or generated value.
     */
    public static function remember( $key, callable $callback, $ttl = 0 ) {
        $value = self::get( $key );
        
        if ( $value !== null ) {
            return $value;
        }

        $value = call_user_func( $callback );
        self::set( $key, $value, $ttl );
        
        return $value;
    }

    /**
     * Normalize cache key (remove invalid characters, add prefix).
     *
     * @param string $key Original key.
     * @return string Normalized key.
     */
    private static function normalize_key( $key ) {
        // Add prefix
        $key = 'mt_primelink_' . $key;
        
        // Remove invalid characters (WooCommerce transients have a 45 char limit for option_name)
        // Symfony Cache can handle longer keys, but we normalize for compatibility
        $key = preg_replace( '/[^a-zA-Z0-9_\-]/', '_', $key );
        
        // Limit length for WooCommerce compatibility (45 chars max for option_name)
        // But keep longer for Symfony Cache by using a hash for the suffix
        if ( strlen( $key ) > 40 ) {
            $hash = substr( md5( $key ), 0, 8 );
            $key = substr( $key, 0, 32 ) . '_' . $hash;
        }
        
        return $key;
    }
}

