<?php

declare(strict_types=1);

namespace App\Framework\Discovery\Commands;

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheKey;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Core\PathProvider;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\DateTime\Clock;
use App\Framework\Discovery\Storage\DiscoveryCacheManager;
use App\Framework\Filesystem\Storage;

/**
 * Unified console commands for clearing discovery-related caches
 *
 * Consolidates functionality from both Discovery and Core cache clearing commands:
 * - discovery:clear-cache: Clear only Discovery service cache
 * - discovery:clear: Clear all discovery-related caches (Discovery + Routes + Legacy)
 * - routes:clear: Clear only routes cache
 */
final readonly class ClearDiscoveryCache
{
    public function __construct(
        private DiscoveryCacheManager $discoveryCacheManager,
        private ConsoleOutput $output,
        private Cache $cache,
        private Clock $clock,
        private PathProvider $pathProvider,
        private Storage $fileSystem
    ) {
    }

    #[ConsoleCommand(name: 'discovery:clear-cache', description: 'Clear Discovery cache')]
    public function handle(): int
    {
        $this->output->writeLine('Clearing Discovery cache...');

        try {
            if ($this->discoveryCacheManager->clearAll()) {
                $this->output->writeLine('<success>Discovery cache cleared successfully!</success>');

                return 0;
            } else {
                $this->output->writeLine('<error>Failed to clear Discovery cache - clearAll returned false</error>');

                return 1;
            }
        } catch (\Throwable $e) {
            $this->output->writeLine('<error>Failed to clear Discovery cache: ' . $e->getMessage() . '</error>');

            return 1;
        }
    }

    #[ConsoleCommand(name: 'discovery:clear', description: 'Clear all discovery-related caches')]
    public function clearAll(): int
    {
        $this->output->writeLine('Clearing all discovery-related caches...');

        $success = true;

        // Clear discovery cache using the cache manager
        if ($this->discoveryCacheManager->clearAll()) {
            $this->output->writeLine('✓ Discovery cache cleared');
        } else {
            $this->output->writeLine('✗ Failed to clear Discovery cache');
            $success = false;
        }

        // Clear legacy cache keys from old Core command
        $this->cache->forget(CacheKey::fromString('discovery_service'));
        $this->cache->forget(CacheKey::fromString('unified_discovery_results'));
        $this->output->writeLine('✓ Legacy discovery cache keys cleared');

        // Clear routes cache
        if ($this->clearRoutesCache()) {
            $this->output->writeLine('✓ Routes cache cleared');
        } else {
            $this->output->writeLine('✗ Failed to clear routes cache');
            $success = false;
        }

        // Clear ALL file cache entries (since we can't selectively delete by prefix due to MD5 hashing)
        $deletedFiles = $this->clearAllFileCache();
        $this->output->writeLine("✓ Cleared {$deletedFiles} file cache entries");

        if ($success) {
            $this->output->writeLine('<success>All discovery caches cleared successfully!</success>');

            return 0;
        } else {
            $this->output->writeLine('<error>Some caches could not be cleared</error>');

            return 1;
        }
    }

    #[ConsoleCommand(name: 'routes:clear', description: 'Clear routes cache')]
    public function clearRoutes(ConsoleInput $input, ConsoleOutput $output): int
    {
        if ($this->clearRoutesCache()) {
            $output->writeLine('<success>Routes cache cleared successfully!</success>');

            return 0;
        } else {
            $output->writeLine('<error>Routes cache not found or could not be cleared</error>');

            return 1;
        }
    }

    /**
     * Clear routes cache file
     */
    private function clearRoutesCache(): bool
    {
        $routesCachePath = $this->pathProvider->resolvePath('/cache/routes.cache.php');

        if (! file_exists($routesCachePath)) {
            return true; // Consider it success if file doesn't exist
        }

        return unlink($routesCachePath);
    }

    /**
     * Clear ALL file cache entries
     *
     * Note: We clear all cache files because FileCache uses MD5 hashing for filenames,
     * making it impossible to selectively delete by cache key prefix.
     * This is necessary until we implement cache tags or a better storage mechanism.
     */
    private function clearAllFileCache(): int
    {
        $cacheDir = $this->pathProvider->resolvePath('/storage/cache');

        $deletedCount = 0;

        try {
            // Use DirectoryIterator for large directories (handles 80K+ files)
            $iterator = new \DirectoryIterator($cacheDir);

            foreach ($iterator as $fileInfo) {
                if ($fileInfo->isDot() || ! $fileInfo->isFile()) {
                    continue;
                }

                $filename = $fileInfo->getFilename();

                // Only delete .cache.php files (keep .lock files for now)
                if (! str_ends_with($filename, '.cache.php')) {
                    continue;
                }

                try {
                    $this->fileSystem->delete($fileInfo->getPathname());
                    $deletedCount++;
                } catch (\Throwable $e) {
                    // Continue with next file if deletion fails
                    continue;
                }
            }
        } catch (\Throwable $e) {
            // If directory iteration fails, return 0
            return 0;
        }

        return $deletedCount;
    }
}
