<?php

declare(strict_types=1);

namespace ProRank\SEO\CLI;

use ProRank\SEO\Modules\Performance\ModernCacheModule;
use WP_CLI;

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

/**
 * ProRank page cache control.
 *
 * ## EXAMPLES
 *
 *     # Purge every cached page
 *     wp prorank cache purge
 *
 *     # Purge a single URL
 *     wp prorank cache purge --url=https://example.com/about
 *
 *     # Quick status of the cache directory
 *     wp prorank cache status
 *
 *     # Show the cache directory path
 *     wp prorank cache path
 */
class CacheCommand {

    /**
     * Purge cached pages.
     *
     * ## OPTIONS
     *
     * [--url=<url>]
     * : Purge a single URL instead of the entire cache.
     *
     * @when after_wp_load
     */
    public function purge($args, $assoc_args): void {
        $module = new ModernCacheModule();

        if (!empty($assoc_args['url'])) {
            $url = (string) $assoc_args['url'];
            $count = $module->clear_urls_cache([$url]);
            if ($count > 0) {
                WP_CLI::success(sprintf('Purged %d cached entr%s for %s', $count, $count === 1 ? 'y' : 'ies', $url));
            } else {
                WP_CLI::warning('No cached entry matched ' . $url);
            }
            return;
        }

        $module->clear_all_cache();
        WP_CLI::success('Page cache purged.');
    }

    /**
     * Purge cached pages by cache tag.
     *
     * ## OPTIONS
     *
     * <tag>
     * : Cache tag to purge. Examples: post:42, post_type:product,
     *   term:category:7, author:3, front_page, home.
     *
     * ## EXAMPLES
     *
     *     # Purge every cached page that references post 42
     *     wp prorank cache purge-tag post:42
     *
     *     # Purge all cached pages tagged with the "category" term 7
     *     wp prorank cache purge-tag term:category:7
     *
     * @subcommand purge-tag
     * @when after_wp_load
     */
    public function purge_tag($args, $assoc_args): void {
        $tag = isset($args[0]) ? (string) $args[0] : '';
        if ($tag === '') {
            WP_CLI::error('You must provide a cache tag, e.g. "post:42".');
        }

        $module = new ModernCacheModule();
        $count  = $module->purge_by_tag($tag);

        if ($count < 0) {
            WP_CLI::success('Tag index was unavailable; performed a full cache purge as a fallback.');
            return;
        }

        if ($count === 0) {
            WP_CLI::warning(sprintf('No cached pages were tagged with %s.', $tag));
            return;
        }

        WP_CLI::success(sprintf('Purged %d cached file%s tagged with %s.', $count, $count === 1 ? '' : 's', $tag));
    }

    /**
     * Report the current cache directory size and file count.
     *
     * @when after_wp_load
     */
    public function status(): void {
        $info = $this->collect_cache_dir_info();

        if (!$info['exists']) {
            WP_CLI::warning('Cache directory does not exist: ' . $info['path']);
            return;
        }

        WP_CLI::log('Cache directory : ' . $info['path']);
        WP_CLI::log('Entries         : ' . $info['files']);
        WP_CLI::log('Total size      : ' . size_format((int) $info['bytes']));
        if ($info['newest'] !== null) {
            WP_CLI::log('Newest entry    : ' . gmdate('Y-m-d H:i:s', $info['newest']) . ' UTC');
        }
        if ($info['oldest'] !== null) {
            WP_CLI::log('Oldest entry    : ' . gmdate('Y-m-d H:i:s', $info['oldest']) . ' UTC');
        }
    }

    /**
     * Print the cache directory path.
     *
     * @when after_wp_load
     */
    public function path(): void {
        $info = $this->collect_cache_dir_info();
        WP_CLI::log($info['path']);
    }

    /**
     * Walk the cache directory once and report aggregate stats.
     *
     * @return array{path:string,exists:bool,files:int,bytes:int,newest:?int,oldest:?int}
     */
    private function collect_cache_dir_info(): array {
        $uploads = function_exists('wp_get_upload_dir') ? wp_get_upload_dir() : [];
        $basedir = isset($uploads['basedir']) ? trailingslashit((string) $uploads['basedir']) : '';
        $cache_dir = $basedir . 'prorank-cache/html';

        if (!is_dir($cache_dir)) {
            return [
                'path'   => $cache_dir,
                'exists' => false,
                'files'  => 0,
                'bytes'  => 0,
                'newest' => null,
                'oldest' => null,
            ];
        }

        $files = 0;
        $bytes = 0;
        $newest = null;
        $oldest = null;

        $iter = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($cache_dir, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($iter as $file) {
            if (!$file instanceof \SplFileInfo || !$file->isFile()) {
                continue;
            }
            $files++;
            $bytes += (int) $file->getSize();
            $mtime = (int) $file->getMTime();
            $newest = $newest === null ? $mtime : max($newest, $mtime);
            $oldest = $oldest === null ? $mtime : min($oldest, $mtime);
        }

        return [
            'path'   => $cache_dir,
            'exists' => true,
            'files'  => $files,
            'bytes'  => $bytes,
            'newest' => $newest,
            'oldest' => $oldest,
        ];
    }
}

if (defined('WP_CLI') && WP_CLI) {
    WP_CLI::add_command('prorank cache', 'ProRank\\SEO\\CLI\\CacheCommand');
}
