<?php
/**
 * Copyright (C) 2026 Plugixa (https://plugixa.com)
 * License: GNU General Public License v2 or later
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 */

namespace PlugixaRecipe\Frontend;

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.SlowDBQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom-table data layer: table identifiers are built with $wpdb->prefix and are never user input; all request values are bound via $wpdb->prepare(); ORDER BY / LIMIT fragments come out of internal allow-list maps; content reads go through PlugixaRecipe\Cache (the static sniff cannot trace caching through the wrapper); meta_key/meta_value are dedicated plugin columns, not WP_Query.

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- $pxr_archive_data is the documented hand-off global read by templates/archive-recipes.php. "pxr" is the plugin's established public prefix (CSS classes, --pxr-* custom properties, pxr_* transients) and is unique to it; the sniff only objects because it is under its 4-character minimum.

defined( 'ABSPATH' ) || exit;

/**
 * RecipeArchive Class — Handles category and cuisine archive pages.
 *
 * Registers rewrite rules for /recipe-category/{slug}/ and /recipe-cuisine/{slug}/
 * and renders an archive page with a recipe grid.
 */
class RecipeArchive {

    /**
     * Initialize archive page hooks.
     */
    public function init(): void {
        add_action( 'init', [ $this, 'register_rewrite_rules' ] );
        add_filter( 'query_vars', [ $this, 'register_query_vars' ] );
        add_filter( 'template_include', [ $this, 'handle_archive' ] );
    }

    /**
     * Register archive rewrite rules.
     */
    public function register_rewrite_rules(): void {
        // Category archive
        add_rewrite_rule(
            '^recipe-category/([^/]+)/page/(\d+)/?$',
            'index.php?pxr_archive_type=category&pxr_archive_slug=$matches[1]&pxr_archive_page=$matches[2]',
            'top'
        );
        add_rewrite_rule(
            '^recipe-category/([^/]+)/?$',
            'index.php?pxr_archive_type=category&pxr_archive_slug=$matches[1]',
            'top'
        );

        // Cuisine archive
        add_rewrite_rule(
            '^recipe-cuisine/([^/]+)/page/(\d+)/?$',
            'index.php?pxr_archive_type=cuisine&pxr_archive_slug=$matches[1]&pxr_archive_page=$matches[2]',
            'top'
        );
        add_rewrite_rule(
            '^recipe-cuisine/([^/]+)/?$',
            'index.php?pxr_archive_type=cuisine&pxr_archive_slug=$matches[1]',
            'top'
        );

        // Auto-flush rewrite rules once when archive feature is first available
        $flushed_version = get_option( 'pxr_archive_rules_flushed', '' );
        if ( $flushed_version !== '1.0' ) {
            flush_rewrite_rules();
            update_option( 'pxr_archive_rules_flushed', '1.0' );
        }
    }

    /**
     * Register custom query variables.
     */
    public function register_query_vars( array $vars ): array {
        $vars[] = 'pxr_archive_type';
        $vars[] = 'pxr_archive_slug';
        $vars[] = 'pxr_archive_page';
        return $vars;
    }

    /**
     * Handle archive page rendering via template_include.
     */
    public function handle_archive( string $template ): string {
        $type = get_query_var( 'pxr_archive_type' );
        $slug = get_query_var( 'pxr_archive_slug' );

        if ( empty( $type ) || empty( $slug ) ) {
            return $template;
        }

        $type = sanitize_key( $type );
        $slug = sanitize_title( $slug );

        if ( ! in_array( $type, [ 'category', 'cuisine' ], true ) ) {
            return $template;
        }

        // Look up taxonomy
        $taxonomy = $this->get_taxonomy_by_slug( $type, $slug );
        if ( ! $taxonomy ) {
            return $template;
        }

        $page     = max( 1, absint( get_query_var( 'pxr_archive_page', 1 ) ) );
        $per_page = 12;

        // Count total recipes
        $total = $this->count_recipes_for_taxonomy( $type, (int) $taxonomy->id );
        $total_pages = max( 1, (int) ceil( $total / $per_page ) );

        // Query recipes for this page
        $recipes = $this->query_recipes_for_taxonomy( $type, (int) $taxonomy->id, $page, $per_page );

        // Enrich recipes for recipe-card.php
        $widget_shortcodes = new WidgetShortcodes();
        // We need to enrich using the private method — duplicate the logic here
        $enriched = [];
        foreach ( $recipes as $recipe ) {
            $enriched[] = $this->enrich_recipe_for_archive( (array) $recipe );
        }

        // Prevent 404
        global $wp_query;
        $wp_query->is_404 = false;
        status_header( 200 );

        // SEO: Set page title
        add_filter( 'document_title_parts', function ( $parts ) use ( $taxonomy, $type ) {
            $type_label = $type === 'category'
                ? __( 'Category', 'plugixarecipe' )
                : __( 'Cuisine', 'plugixarecipe' );
            $parts['title'] = sprintf(
                /* translators: 1: taxonomy name, 2: type label */
                __( '%1$s %2$s Recipes', 'plugixarecipe' ),
                $taxonomy->name,
                $type_label
            );
            return $parts;
        } );

        // Body classes
        add_filter( 'body_class', function ( $classes ) use ( $type ) {
            $classes = array_diff( $classes, [ 'home', 'blog' ] );
            $classes[] = 'wp-singular';
            $classes[] = 'pxr-archive';
            $classes[] = 'pxr-archive-' . $type;
            return $classes;
        } );

        // Enqueue frontend CSS
        $css_path = PLUGIXARECIPE_PATH . 'assets/frontend/build/css/frontend.css';
        if ( file_exists( $css_path ) ) {
            wp_enqueue_style(
                'plugixarecipe-frontend',
                PLUGIXARECIPE_URL . 'assets/frontend/build/css/frontend.css',
                [],
                PLUGIXARECIPE_VERSION
            );
        }

        // Enqueue frontend JS
        $js_path = PLUGIXARECIPE_PATH . 'assets/frontend/js/recipes.js';
        if ( file_exists( $js_path ) ) {
            wp_enqueue_script(
                'plugixarecipe-frontend',
                PLUGIXARECIPE_URL . 'assets/frontend/js/recipes.js',
                [],
                PLUGIXARECIPE_VERSION,
                true
            );
            wp_localize_script( 'plugixarecipe-frontend', 'pxrConfig', [
                'ajaxUrl'    => admin_url( 'admin-ajax.php' ),
                'restUrl'    => esc_url_raw( rest_url( 'plugixarecipe/v1/' ) ),
                'nonce'      => wp_create_nonce( 'pxr_frontend' ),
                'restNonce'  => wp_create_nonce( 'wp_rest' ),
                'isLoggedIn' => is_user_logged_in(),
                'loginUrl'   => wp_login_url( get_permalink() ),
                'i18n'       => [
                    'tooltip' => [
                        'like'       => __( 'Like this recipe', 'plugixarecipe' ),
                        'likeActive' => __( 'Unlike this recipe', 'plugixarecipe' ),
                        'save'       => __( 'Save to favorites', 'plugixarecipe' ),
                        'saveActive' => __( 'Remove from saved', 'plugixarecipe' ),
                        'loginLike'  => __( 'Log in to like this recipe', 'plugixarecipe' ),
                        'loginSave'  => __( 'Log in to save this recipe', 'plugixarecipe' ),
                        'loginLink'  => __( 'Log in', 'plugixarecipe' ),
                    ],
                ],
            ] );
        }

        // Build archive base URL for pagination
        $archive_base = $type === 'category' ? 'recipe-category' : 'recipe-cuisine';

        // Pass data to template via globals (same pattern as RecipeSingle)
        $GLOBALS['pxr_archive_data'] = [
            'taxonomy'     => $taxonomy,
            'type'         => $type,
            'recipes'      => $enriched,
            'page'         => $page,
            'total_pages'  => $total_pages,
            'total'        => $total,
            'per_page'     => $per_page,
            'archive_base' => $archive_base,
            'view_config'  => $this->get_default_view_config(),
        ];

        return PLUGIXARECIPE_PATH . 'templates/archive-wrapper.php';
    }

    /**
     * Look up a taxonomy item by slug.
     */
    private function get_taxonomy_by_slug( string $type, string $slug ): ?object {
        global $wpdb;
        $prefix = $wpdb->prefix . 'plugixarecipe_';
        $table  = $type === 'category' ? 'categories' : 'cuisines';

        $result = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$prefix}{$table} WHERE slug = %s LIMIT 1",
            $slug
        ) );

        return $result ?: null;
    }

    /**
     * Count recipes in a taxonomy.
     */
    private function count_recipes_for_taxonomy( string $type, int $taxonomy_id ): int {
        global $wpdb;
        $prefix      = $wpdb->prefix . 'plugixarecipe_';
        $pivot_table = $type === 'category' ? 'recipe_categories' : 'recipe_cuisines';
        $pivot_fk    = $type === 'category' ? 'category_id' : 'cuisine_id';

        return (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(DISTINCT r.id) FROM {$prefix}recipes r
             INNER JOIN {$prefix}{$pivot_table} p ON r.id = p.recipe_id
             WHERE p.{$pivot_fk} = %d AND r.status = 'published'",
            $taxonomy_id
        ) );
    }

    /**
     * Query paginated recipes for a taxonomy.
     */
    private function query_recipes_for_taxonomy( string $type, int $taxonomy_id, int $page, int $per_page ): array {
        global $wpdb;
        $prefix      = $wpdb->prefix . 'plugixarecipe_';
        $pivot_table = $type === 'category' ? 'recipe_categories' : 'recipe_cuisines';
        $pivot_fk    = $type === 'category' ? 'category_id' : 'cuisine_id';
        $offset      = ( $page - 1 ) * $per_page;

        return $wpdb->get_results( $wpdb->prepare(
            "SELECT r.* FROM {$prefix}recipes r
             INNER JOIN {$prefix}{$pivot_table} p ON r.id = p.recipe_id
             WHERE p.{$pivot_fk} = %d AND r.status = 'published'
             ORDER BY r.created_at DESC
             LIMIT %d OFFSET %d",
            $taxonomy_id,
            $per_page,
            $offset
        ), ARRAY_A );
    }

    /**
     * Enrich a recipe for recipe-card.php (archive context).
     */
    private function enrich_recipe_for_archive( array $recipe ): object {
        global $wpdb;
        $prefix    = $wpdb->prefix . 'plugixarecipe_';
        $recipe_id = (int) $recipe['id'];

        // Image
        if ( ! empty( $recipe['image_id'] ) ) {
            $recipe['image_url']    = wp_get_attachment_image_url( (int) $recipe['image_id'], 'medium_large' ) ?: '';
            $recipe['image_srcset'] = wp_get_attachment_image_srcset( (int) $recipe['image_id'], 'medium_large' ) ?: '';
        } else {
            $recipe['image_url']    = '';
            $recipe['image_srcset'] = '';
        }

        // Categories
        $recipe['categories'] = $wpdb->get_results( $wpdb->prepare(
            "SELECT c.id, c.name, c.slug FROM {$prefix}categories c
             INNER JOIN {$prefix}recipe_categories rc ON c.id = rc.category_id
             WHERE rc.recipe_id = %d ORDER BY rc.display_order ASC",
            $recipe_id
        ), ARRAY_A );

        // Cuisines
        $recipe['cuisines'] = $wpdb->get_results( $wpdb->prepare(
            "SELECT cu.id, cu.name, cu.slug FROM {$prefix}cuisines cu
             INNER JOIN {$prefix}recipe_cuisines rcu ON cu.id = rcu.cuisine_id
             WHERE rcu.recipe_id = %d",
            $recipe_id
        ), ARRAY_A );

        // Diet badges
        $recipe['diet_badges'] = [];
        if ( ! empty( $recipe['is_vegetarian'] ) ) $recipe['diet_badges'][] = __( 'Vegetarian', 'plugixarecipe' );
        if ( ! empty( $recipe['is_vegan'] ) )      $recipe['diet_badges'][] = __( 'Vegan', 'plugixarecipe' );
        if ( ! empty( $recipe['is_gluten_free'] ) ) $recipe['diet_badges'][] = __( 'Gluten-Free', 'plugixarecipe' );
        if ( ! empty( $recipe['is_dairy_free'] ) )  $recipe['diet_badges'][] = __( 'Dairy-Free', 'plugixarecipe' );
        if ( ! empty( $recipe['is_keto'] ) )        $recipe['diet_badges'][] = __( 'Keto', 'plugixarecipe' );
        if ( ! empty( $recipe['is_low_carb'] ) )    $recipe['diet_badges'][] = __( 'Low-Carb', 'plugixarecipe' );

        // Excerpt
        if ( ! empty( $recipe['description'] ) ) {
            $plain = wp_strip_all_tags( $recipe['description'] );
            $recipe['excerpt'] = mb_strlen( $plain ) > 150
                ? mb_substr( $plain, 0, 150 ) . "\u{2026}"
                : $plain;
        } else {
            $recipe['excerpt'] = '';
        }

        // Like/favorite
        $recipe['like_count'] = isset( $recipe['like_count'] ) ? (int) $recipe['like_count'] : 0;
        if ( is_user_logged_in() ) {
            $uid = get_current_user_id();
            $recipe['is_liked']     = (bool) $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$prefix}likes WHERE user_id = %d AND recipe_id = %d", $uid, $recipe_id
            ) );
            $recipe['is_favorited'] = (bool) $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$prefix}favorites WHERE user_id = %d AND recipe_id = %d", $uid, $recipe_id
            ) );
        } else {
            $recipe['is_liked']     = false;
            $recipe['is_favorited'] = false;
        }

        // Aliases
        $recipe['rating']    = $recipe['rating_average'] ?? 0;
        $recipe['cuisine']   = ! empty( $recipe['cuisines'][0]['name'] ) ? $recipe['cuisines'][0]['name'] : '';
        $slug                = sanitize_title( $recipe['title'] ?? '' );
        $recipe['permalink'] = home_url( "/recipe/{$recipe_id}/{$slug}/" );
        $recipe['print_url'] = home_url( "/recipe-print/{$recipe_id}/?auto=1" );

        return (object) $recipe;
    }

    /**
     * Get default view config for archive grid display.
     */
    private function get_default_view_config(): array {
        return [
            'show_image'      => true,
            'show_rating'     => true,
            'show_meta'       => true,
            'show_difficulty' => true,
            'show_diet'       => false,
            'show_cuisine'    => false,
            'show_excerpt'    => true,
            'layout' => [
                'style'   => 'grid',
                'columns' => [ 'desktop' => 3, 'tablet' => 2, 'mobile' => 1 ],
            ],
        ];
    }
}
