<?php

namespace Miruni;

use WP_Post;

if (!defined('ABSPATH'))
    exit; // Exit if accessed directly


use Exception;

/**
 * Utility class for handling post meta operations
 */
class Miruni_Post_Meta_Utils
{
    /**
     * Updates a value in a post meta array
     * 
     * @param int $post_id The ID of the post to update meta for
     * @param Miruni_Preview_Meta_Keys::* $meta_key The meta key for the array
     * @param string|int $item_key The key within the array to update
     * @param mixed $item_value The new value to set
     * @param ?string $log_message Optional message to log
     * @return bool Success status
     */
    public static function update_meta_array_item(
        int $post_id,
        string $meta_key,
        string|int $item_key,
        mixed $item_value,
        ?string $log_message = null
    ): bool {
        try {
            error_log("Updating post meta array: {$meta_key} for post ID: {$post_id} - type: " . gettype($item_value));
            // Log message if provided
            if ($log_message) {
                do_action('miruni_error', new Exception($log_message), [
                    'context' => [
                        'post_id' => $post_id,
                        'meta_key' => $meta_key,
                        'item_key' => $item_key,
                        'item_value' => $item_value
                    ],
                    'operation' => 'Update Meta Array Item',
                    'user_id' => get_current_user_id()
                ]);
            }

            // Get existing changes if any
            $changes = get_post_meta($post_id, $meta_key, true);
            if (!is_array($changes)) {
                $changes = [];
            }
            // Add or update the item
            $changes[$item_key] = $item_value;

            // Save to post meta
            update_post_meta($post_id, $meta_key, $changes);

            return true;
        } catch (Exception $e) {
            error_log($e->getMessage());
            do_action('miruni_error', $e, [
                'context' => [
                    'post_id' => $post_id,
                    'meta_key' => $meta_key,
                    'item_key' => $item_key
                ],
                'operation' => 'Failed to update post meta array',
                'user_id' => get_current_user_id()
            ]);
            return false;
        }
    }

    /**
     * Apply transient title changes
     * 
     * @param int $draft_id The draft post ID
     * @param array<int,string> $existing_changes Existing title changes to avoid duplication
     * @return array<int,string> Updated title changes
     */
    public static function apply_transient_title_changes(int $draft_id, array $existing_changes = []): array
    {
        $title_changes = $existing_changes;
        $transient_key = 'miruni_preview_titles_' . $draft_id;
        $transient_title_changes = get_transient($transient_key);

        if (is_array($transient_title_changes) && !empty($transient_title_changes)) {
            foreach ($transient_title_changes as $post_id => $new_title) {
                if (!isset($title_changes[$post_id])) { // Don't duplicate if already processed from meta
                    $result = wp_update_post([
                        'ID' => $post_id,
                        'post_title' => $new_title
                    ]);

                    if ($result) {
                        $title_changes[$post_id] = $new_title;
                    }
                }
            }
        }

        return $title_changes;
    }

    /**
     * Apply theme mod changes from both post meta and transients
     * 
     * @param int $draft_id The draft post ID
     * @return array<string,mixed> Applied theme mods
     */
    public static function apply_theme_mod_changes(int $draft_id): array
    {
        $theme_mod_changes = get_post_meta($draft_id, Miruni_Preview_Meta_Keys::THEME_MODS, true);
        $transient_theme_mods = get_transient('miruni_preview_theme_mods_' . $draft_id);
        $applied_mods = [];

        // Merge and apply theme mod changes
        if (is_array($theme_mod_changes) || is_array($transient_theme_mods)) {
            $combined_mods = array_merge(
                is_array($theme_mod_changes) ? $theme_mod_changes : [],
                is_array($transient_theme_mods) ? $transient_theme_mods : []
            );

            foreach ($combined_mods as $mod_name => $value) {
                set_theme_mod($mod_name, $value);
                $applied_mods[$mod_name] = $value;
            }
        }

        return $applied_mods;
    }

    /**
     * Apply WordPress option changes
     * 
     * @param int $draft_id The draft post ID
     * @return array<string,mixed> Applied options
     */
    public static function apply_wp_option_changes(int $draft_id): array
    {
        $applied_options = [];
        $wp_option_changes = get_post_meta($draft_id, Miruni_Preview_Meta_Keys::WP_OPTIONS, true);

        if (is_array($wp_option_changes)) {
            foreach ($wp_option_changes as $option_name => $value) {
                do_action('miruni_error', new Exception("Updating WP option: {$option_name}"), [
                    'context' => [
                        'draft_id' => $draft_id,
                        'option_name' => $option_name,
                        'value' => $value
                    ],
                    'operation' => 'Update WordPress Option',
                    'user_id' => get_current_user_id()
                ]);
                update_option($option_name, $value);
                $applied_options[$option_name] = $value;
            }
        }

        return $applied_options;
    }

    /**
     * Apply menu item name and order changes
     * 
     * @param int $draft_id The draft post ID
     * @return array<int,string> Applied menu item name changes (keyed by menu_item_id)
     */
    public static function apply_menu_item_changes(int $draft_id): array
    {
        $applied_changes = [];
        $menu_item_names = get_post_meta($draft_id, Miruni_Preview_Meta_Keys::MENU_ITEM_NAME, true);
        $menu_item_order = get_post_meta($draft_id, Miruni_Preview_Meta_Keys::MENU_ITEM_ORDER, true);

        // Ensure we have arrays to work with
        $menu_item_names = is_array($menu_item_names) ? $menu_item_names : [];
        $menu_item_order = is_array($menu_item_order) ? $menu_item_order : [];

        // Get unique list of all menu item IDs that need processing
        $all_menu_item_ids = array_unique(array_merge(array_keys($menu_item_names), array_keys($menu_item_order)));

        if (empty($all_menu_item_ids)) {
            return $applied_changes; // No changes to apply
        }

        do_action('miruni_error', new Exception("Applying menu item changes"), [
            'context' => [
                'draft_id' => $draft_id,
                'menu_item_names_count' => count($menu_item_names),
                'menu_item_order_count' => count($menu_item_order),
                'total_items_to_process' => count($all_menu_item_ids)
            ],
            'operation' => 'Apply Menu Item Changes',
            'user_id' => get_current_user_id()
        ]);

        foreach ($all_menu_item_ids as $menu_item_id) {
            // Validate menu item ID
            if (!is_int($menu_item_id) || $menu_item_id <= 0) {
                do_action('miruni_error', new Exception("Invalid menu item ID encountered: " . print_r($menu_item_id, true)), [
                    'context' => ['draft_id' => $draft_id],
                    'operation' => 'Apply Menu Item Changes',
                    'user_id' => get_current_user_id()
                ]);
                continue;
            }

            // Check if menu item post exists
            $menu_item_post = get_post($menu_item_id);
            if (!($menu_item_post instanceof WP_Post) || $menu_item_post->post_type !== 'nav_menu_item') {
                do_action('miruni_error', new Exception("Menu item post not found or invalid type for ID {$menu_item_id}"), [
                    'context' => ['draft_id' => $draft_id, 'menu_item_id' => $menu_item_id],
                    'operation' => 'Apply Menu Item Changes',
                    'user_id' => get_current_user_id()
                ]);
                continue;
            }

            // Prepare arguments for wp_update_post
            $update_args = ['ID' => $menu_item_id];
            $has_changes = false;

            // Check for name change
            if (isset($menu_item_names[$menu_item_id])) {
                $new_name = $menu_item_names[$menu_item_id];
                if (is_string($new_name)) { // Basic validation
                    $update_args['post_title'] = $new_name;
                    $has_changes = true;
                }
            }

            // Check for order change
            if (isset($menu_item_order[$menu_item_id])) {
                $new_order = $menu_item_order[$menu_item_id];
                if (is_numeric($new_order)) { // Basic validation
                    $update_args['menu_order'] = (int) $new_order;
                    $has_changes = true;
                }
            }

            // Update the post if there are changes
            if ($has_changes) {
                $result = wp_update_post($update_args, true); // Pass true to enable WP_Error return

                if (is_wp_error($result)) {
                    do_action('miruni_error', new Exception("Failed to update menu item {$menu_item_id}: " . $result->get_error_message()), [
                        'context' => ['draft_id' => $draft_id, 'menu_item_id' => $menu_item_id, 'update_args' => $update_args],
                        'operation' => 'Apply Menu Item Changes',
                        'user_id' => get_current_user_id()
                    ]);
                } else {
                    // Track applied name changes if name was part of the update
                    if (isset($update_args['post_title'])) {
                        $applied_changes[$menu_item_id] = $update_args['post_title'];
                    }
                }
            }
        }

        return $applied_changes;
    }

    /**
     * Apply block template changes
     * 
     * @param int $draft_id The draft post ID
     * @return array<string,bool> Applied block template changes
     */
    public static function apply_block_template_changes(int $draft_id): array
    {
        $applied_changes = [];
        $block_templates = get_post_meta($draft_id, Miruni_Preview_Meta_Keys::BLOCK_TEMPLATE, true);

        if (!is_array($block_templates) || empty($block_templates)) {
            return $applied_changes;
        }

        do_action('miruni_error', new Exception("Applying block template changes"), [
            'context' => [
                'draft_id' => $draft_id,
                'block_templates' => $block_templates
            ],
            'operation' => 'Apply Block Template Changes',
            'user_id' => get_current_user_id()
        ]);

        foreach ($block_templates as $template_slug => $template_content) {
            // Skip if no content
            if (empty($template_content)) {
                continue;
            }

            // For theme templates, we need to get the active theme
            $current_theme = get_stylesheet();

            // Determine template type (template or template part)
            $template_type = 'wp_template';
            if (strpos($template_slug, 'template-parts/') === 0) {
                $template_type = 'wp_template_part';
                // Remove the template-parts/ prefix for proper slug
                $template_slug = str_replace('template-parts/', '', $template_slug);
            }

            // Try to find existing template
            $template_post = null;

            // Query for existing customized template
            $query_args = [
                'post_type' => $template_type,
                'post_status' => ['publish', 'auto-draft'],
                'name' => $template_slug,
                'posts_per_page' => 1,
                'no_found_rows' => true,
                'tax_query' => [
                    [
                        'taxonomy' => 'wp_theme',
                        'field' => 'name',
                        'terms' => $current_theme
                    ]
                ],
            ];

            $template_query = new \WP_Query($query_args);

            if ($template_query->have_posts()) {
                $template_post = $template_query->posts[0];
            }

            // If template exists, update it
            if ($template_post && $template_post instanceof \WP_Post) {
                $update_args = [
                    'ID' => $template_post->ID,
                    'post_content' => $template_content,
                ];

                wp_update_post($update_args);

                $applied_changes[$template_slug] = true;

            } else {
                // Template doesn't exist, create a new one
                $insert_args = [
                    'post_type' => $template_type,
                    'post_name' => $template_slug,
                    'post_title' => ucwords(str_replace(['-', '_'], ' ', $template_slug)),
                    'post_content' => $template_content,
                    'post_status' => 'publish',
                    'tax_input' => [
                        'wp_theme' => [$current_theme]
                    ]
                ];

                $new_id = wp_insert_post($insert_args);

                // @phpstan-ignore function.impossibleType
                if ($new_id && !is_wp_error($new_id)) {
                    // Set the theme for the template
                    wp_set_post_terms($new_id, [$current_theme], 'wp_theme');

                    $applied_changes[$template_slug] = true;
                    do_action('miruni_error', new Exception("Created new template: {$template_slug} (ID: {$new_id})"), [
                        'context' => [
                            'draft_id' => $draft_id,
                            'template_slug' => $template_slug,
                            'new_id' => $new_id
                        ],
                        'operation' => 'Create New Block Template',
                        'user_id' => get_current_user_id()
                    ]);
                } else {
                    do_action('miruni_error', new Exception("Failed to create template: {$template_slug}"), [
                        'context' => [
                            'draft_id' => $draft_id,
                            'template_slug' => $template_slug,
                        ],
                        'operation' => 'Create New Block Template',
                        'user_id' => get_current_user_id()
                    ]);
                }
            }
        }

        return $applied_changes;
    }
}


/**
 * Enum-like class for draft preview meta keys
 */
class Miruni_Preview_Meta_Keys
{

    public const MENU_ITEM_NAME = '_miruni_menu_item_names';
    public const OTHER_POST_TITLES = '_miruni_other_post_titles';
    public const OTHER_POST_CONTENT = '_miruni_other_post_content';
    public const OTHER_POST_EXCERPTS = '_miruni_other_post_excerpts';
    public const THEME_MODS = '_miruni_theme_mods';
    public const WP_OPTIONS = '_miruni_wp_options';
    public const ELEMENTOR_JSON = '_miruni_elementor_json';
    public const BREAKDANCE_DATA = '_miruni_breakdance_data';
    public const BLOCK_TEMPLATE = '_miruni_block_template';
    public const MENU_ITEM_PARENT = '_miruni_menu_item_parent';
    public const MENU_ITEM_URL = '_miruni_menu_item_url';
    public const MENU_ITEM_OBJECT_IDS = '_miruni_menu_item_object_ids';
    public const MENU_ITEM_OBJECTS = '_miruni_menu_item_objects';
    public const MENU_ITEM_ORDER = '_miruni_menu_item_order';
    public const BLOCK_WIDGET = '_miruni_block_widget';
    public const BREAKDANCE_GLOBAL_BLOCK = '_miruni_breakdance_global_block';
    public const THEME_JSON = '_miruni_theme_json';
}

/**
 * Special placeholder post ID values for non-standard WordPress content
 * 
 * The Miruni plugin generally operates on individual WordPress posts with unique post IDs.
 * However, certain WordPress features don't map to specific post IDs (like the "Latest Posts" 
 * homepage). This class provides standardized placeholder values to handle these special cases.
 * 
 * Usage:
 * When a function requires a post ID but you're working with content that doesn't have one,
 * use these constants instead of hardcoding magic numbers in your code.
 * 
 * Example:
 * ```php
 * if ($post_id === Miruni_Post_ID_Placeholder::LATEST_POSTS) {
 *     // Handle latest posts homepage specially
 * }
 * ```
 */
class Miruni_Post_ID_Placeholder
{
    /**
     * Placeholder ID for the "Your Latest Posts" homepage display
     * 
     * WordPress can display recent posts on the homepage without being tied
     * to a specific post ID. Use this constant when you need to reference
     * this special case in functions that normally operate on post IDs.
     * 
     * @var int
     */
    public const LATEST_POSTS = -1;

    // Additional placeholder IDs can be added here as needed
}