<?php

namespace FleekDash\Controllers\Post;

/**
 * Helper for PostController index/list operations.
 * Handles post status normalization and cache key building.
 *
 * @package FleekDash\Controllers\Post
 */
class PostIndexHelper
{
    private const CACHE_PREFIX = 'fleekdash_posts_list_';

    /**
     * Normalize post_status from request params.
     *
     * @param \WP_REST_Request $request
     * @return string|array<int, string>
     */
    public static function normalizePostStatus(\WP_REST_Request $request)
    {
        $status_param = $request->get_param('post_status');
        if ($status_param === null || $status_param === '') {
            $status_param = $request->get_param('status');
        }
        $default = 'publish';
        if ($status_param === null || $status_param === '') {
            return $default;
        }
        $result = is_array($status_param)
            ? self::normalizeArrayStatus($status_param)
            : self::normalizeScalarStatus($status_param);
        return $result ?? $default;
    }

    /**
     * Normalize array status param. Returns 'any', array, or null for default.
     *
     * @param array<int, mixed> $status_param
     * @return string|array<int, string>|null
     */
    private static function normalizeArrayStatus(array $status_param)
    {
        $normalized = array_values(array_filter(array_map(
            static fn ($s) => is_string($s) ? trim($s) : '',
            $status_param
        )));
        $has_all = !empty(array_filter($normalized, static fn ($s) => in_array(strtolower($s), ['all', 'any', '*'], true)));
        if ($has_all) {
            return 'any';
        }
        return !empty($normalized) ? $normalized : null;
    }

    /**
     * Normalize scalar status param. Returns 'any', segments array, string, or null for default.
     *
     * @param mixed $status_param
     * @return string|array<int, string>|null
     */
    private static function normalizeScalarStatus($status_param)
    {
        $normalized = trim((string) $status_param);
        if ($normalized === '' || in_array(strtolower($normalized), ['all', 'any', '*'], true)) {
            return in_array(strtolower($normalized), ['all', 'any', '*'], true) ? 'any' : null;
        }
        if (strpos($normalized, ',') !== false) {
            $segments = array_values(array_filter(array_map('trim', explode(',', $normalized))));
            return !empty($segments) ? $segments : null;
        }
        return $normalized;
    }

    /**
     * Build cache key for posts list transient.
     *
     * @param array<string, mixed> $params
     * @return string
     */
    public static function buildCacheKey(array $params): string
    {
        $post_type = $params['post_type'] ?? 'post';
        $post_status = $params['post_status'] ?? 'publish';
        $page = $params['page'] ?? 1;
        $per_page = $params['per_page'] ?? 10;
        $orderby = $params['orderby'] ?? 'date';
        $order = $params['order'] ?? 'DESC';
        $search = $params['search'] ?? null;
        $taxonomies = $params['taxonomies'] ?? [];

        if (is_array($post_status)) {
            $status_normalized = implode(',', array_map('strval', $post_status));
        } else {
            $status_normalized = (string) $post_status;
        }
        if (is_array($taxonomies)) {
            $tax_array = $taxonomies;
        } else {
            $tax_array = (array) $taxonomies;
        }
        $tax_normalized = !empty($tax_array) ? json_encode($tax_array, JSON_UNESCAPED_UNICODE) : '';
        $hash_input = implode('|', [$post_type, $status_normalized, $page, $per_page, $orderby, $order, $search ?? '', $tax_normalized]);
        return self::CACHE_PREFIX . md5($hash_input);
    }

    /**
     * Build WP_Query args for posts list (reduces complexity in controller).
     *
     * @param array<string, mixed> $params
     * @return array<string, mixed>
     */
    public static function buildQueryArgs(array $params): array
    {
        $args = [
            'post_type' => $params['post_type'] ?? 'post',
            'posts_per_page' => (int) ($params['per_page'] ?? 10),
            'paged' => (int) ($params['page'] ?? 1),
            'orderby' => $params['orderby'] ?? 'date',
            'order' => strtoupper($params['order'] ?? 'DESC'),
            'post_status' => $params['post_status'] ?? 'publish',
            // Prime term/meta caches in bulk. formatPostForGrid() reads terms
            // (category + post_tag) and meta (_thumbnail_id, logo, _wp_page_template)
            // for every row; with these disabled each row triggered separate DB
            // queries (N+1). Bulk priming turns ~1500 per-row queries into a couple
            // of grouped queries for the whole list.
            'update_post_meta_cache' => true,
            'update_post_term_cache' => true,
            'ignore_sticky_posts' => true,
            'cache_results' => true,
        ];
        if (!empty($params['search'])) {
            $args['s'] = $params['search'];
        }
        $taxonomies = $params['taxonomies'] ?? [];
        if (!empty($taxonomies) && is_array($taxonomies)) {
            $tax_query = [];
            foreach ($taxonomies as $taxonomy => $terms) {
                if (!empty($terms)) {
                    $tax_query[] = [
                        'taxonomy' => $taxonomy,
                        'field' => 'term_id',
                        'terms' => is_array($terms) ? $terms : [$terms],
                    ];
                }
            }
            if (!empty($tax_query)) {
                $args['tax_query'] = $tax_query;
            }
        }
        return $args;
    }
}
