<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Format a machine-formatted numeric value (decimal point '.') for display using the
 * current locale's decimal and thousands separators.
 *
 * By default (no $decimals given) trailing zeros are stripped so whole quantities show
 * cleanly (e.g. "3.000" -> "3", "1.400" -> "1,4" in French). Pass an explicit $decimals
 * (e.g. 2 for money) to keep a fixed number of decimals.
 *
 * Use ONLY for human-facing output (PDF, preview, on-screen). Never feed the result back
 * into floatval() or JS data attributes, which expect the machine '.' format.
 *
 * @param string|float|int $value Machine-formatted numeric value.
 * @param int|null         $decimals Force a number of decimals; null = infer & trim zeros.
 * @return string Locale-formatted number.
 */
function tulipwork_orderstock_i18n_number($value, $decimals = null) {
    $float = (float) $value;
    if ($decimals === null) {
        $str = (string) $value;
        $decimals = (strpos($str, '.') !== false) ? strlen(substr(strrchr($str, '.'), 1)) : 0;
        if ($decimals > 0) {
            $clean = rtrim(rtrim(number_format($float, $decimals, '.', ''), '0'), '.');
            $decimals = (strpos($clean, '.') !== false) ? strlen(substr(strrchr($clean, '.'), 1)) : 0;
        }
    }
    return number_format_i18n($float, (int) $decimals);
}

/**
 * Trim trailing zeros from a machine-formatted number ("3.000" -> "3", "1.400" -> "1.4"),
 * keeping the '.' decimal separator. Safe for <input type="number"> value attributes.
 *
 * @param string|float|int $value
 * @return string
 */
function tulipwork_orderstock_trim_zeros($value) {
    $str = (string) $value;
    if (strpos($str, '.') === false) {
        return $str;
    }
    return rtrim(rtrim($str, '0'), '.');
}

/**
 * Format a date/time for display using each language's conventions.
 *
 * The format itself is translatable (msgid "F j, Y g:i a"): English shows
 * "June 19, 2026 2:15 pm", French "19 juin 2026 à 14:15", etc. Month names follow
 * the active locale via date_i18n().
 *
 * @param string|null $value A stored date string (e.g. "Y-m-d H:i:s"); null = now.
 * @return string Localized date/time, or the raw value if it can't be parsed.
 */
function tulipwork_orderstock_i18n_datetime($value = null) {
    $timestamp = $value ? strtotime($value) : current_time('timestamp');
    if (!$timestamp) {
        return (string) $value;
    }
    return date_i18n(__('F j, Y g:i a', 'orderstock'), $timestamp);
}

/**
 * Store a supplier order-confirmation token and return it. Expired tokens are pruned.
 *
 * @param array $data Keys: recipients[], supplier_emails[], company_name, supplier_name, locale.
 * @return string The generated token.
 */
function tulipwork_orderstock_store_confirm_token($data) {
    $tokens = get_option('tulipwork_orderstock_confirm_tokens', []);
    if (!is_array($tokens)) {
        $tokens = [];
    }
    $now = time();
    foreach ($tokens as $key => $entry) {
        if (empty($entry['expires']) || $entry['expires'] < $now) {
            unset($tokens[$key]);
        }
    }
    $token = wp_generate_uuid4();
    $data['expires'] = $now + 30 * DAY_IN_SECONDS;
    $data['confirmed'] = false;
    $tokens[$token] = $data;
    update_option('tulipwork_orderstock_confirm_tokens', $tokens);
    return $token;
}

/**
 * Public URL the supplier clicks to confirm receipt of an order.
 *
 * @param string $token
 * @return string
 */
function tulipwork_orderstock_confirm_url($token) {
    return add_query_arg('tulipwork_order_confirm', rawurlencode($token), home_url('/'));
}

/**
 * The confirmation block appended to the order email sent to the supplier.
 *
 * @param string $url The supplier confirmation URL.
 * @return string Localized, plain-text block.
 */
function tulipwork_orderstock_order_email_confirmation_text($url) {
    return sprintf(
        /* translators: %s is the confirmation link URL. */
        __("To confirm that you have received this order, please click the link below:\n%s\n\nIf you need any changes (products, quantities, or delivery date), simply reply to this email using \"Reply All\" so that everyone stays informed.", 'orderstock'),
        $url
    );
}

/**
 * Build a Reply-To header so replies reach the business, even though the From
 * address stays the WordPress/SMTP default (best for deliverability and SMTP-plugin
 * compatibility). Uses the given company/store email(s), falling back to the WordPress
 * admin email.
 *
 * @param string $email_string One or more comma-separated emails (e.g. the company/store email).
 * @return array wp_mail() headers (empty if no valid address).
 */
function tulipwork_orderstock_reply_to_header($email_string = '') {
    $emails = array_filter(array_map('trim', explode(',', (string) $email_string)), 'is_email');
    if (empty($emails)) {
        $admin_email = get_option('admin_email');
        if (is_email($admin_email)) {
            $emails[] = $admin_email;
        }
    }
    // One "Reply-To:" header line per address. Combining several addresses in a single
    // "Reply-To: a@x, b@x" line is valid RFC 5322 (WP core splits on the comma), but Post
    // SMTP and some other SMTP plugins treat the whole comma-joined string as one address
    // and reject it ("Invalid Reply-To e-mail address"), which makes wp_mail() fail.
    return array_map(static function ($email) {
        return 'Reply-To: ' . $email;
    }, $emails);
}

/**
 * Clean up all OrderStock data for a specific site.
 *
 * @param int  $blog_id           The ID of the blog/site to clean up.
 * @param bool $full_cleanup      If true, deletes all data including Pro data if Pro is active.
 * @param bool $preserve_structure If true, preserves database table structures (e.g., wp_tulipwork_stocks).
 */
function tulipwork_orderstock_cleanup_site($blog_id, $full_cleanup = false, $preserve_structure = false) {
    global $wpdb;

    // En multisite, basculer vers le blog spécifié
    if (is_multisite()) {
        switch_to_blog($blog_id);
    }

    $delete_data = get_option('tulipwork_orderstock_delete_data_on_uninstall', 0);
    $is_pro_active = function_exists('is_plugin_active') && is_plugin_active('orderstock-pro/orderstock-pro.php');

    if ($delete_data || $full_cleanup) {
        // Suppression des options (plugin gratuit)
        $free_options = [
            'tulipwork_orderstock_admin_emails',
            'tulipwork_orderstock_company_name',
            'tulipwork_orderstock_company_address',
            'tulipwork_orderstock_company_phone',
            'tulipwork_orderstock_company_email',
            'tulipwork_orderstock_company_siret',
            'tulipwork_orderstock_tax_rate_1',
            'tulipwork_orderstock_tax_rate_2',
            'tulipwork_orderstock_tax_rate_3',
            'orderstock_order_mode',
            'tulipwork_orderstock_delete_data_on_uninstall',
            'tulipwork_orderstock_supplier_migration_done',
            'tulipwork_orderstock_pdf_tokens',
        ];
        foreach ($free_options as $option) {
            delete_option($option);
        }

        // Suppression des options spécifiques à OrderStock Pro si Pro est actif ou full_cleanup
        if ($is_pro_active || $full_cleanup) {
            $pro_options = [
                'orderstock_pro_central_kitchen_enabled',
                'orderstock_pro_central_kitchen',
                'orderstock_pro_supplier_migration_done',
                // Intégration Zelty
                'orderstock_pro_zelty_enabled',
                'orderstock_pro_zelty_api_key',
                'orderstock_pro_zelty_restaurant_id',
                'orderstock_pro_zelty_api_version',
                'orderstock_pro_zelty_demo_mode',
                'orderstock_pro_zelty_window_days',
                'orderstock_pro_zelty_auto_sync',
                'orderstock_pro_zelty_last_sync',
                'orderstock_pro_zelty_availability_correction',
                'orderstock_pro_zelty_open_weekdays',
                'orderstock_pro_zelty_cron_last_run',
                'orderstock_pro_zelty_cron_last_status',
                'orderstock_pro_open_days',
                'orderstock_pro_recipes_db_version',
                // Ne pas inclure 'orderstock_pro_license_key' et 'orderstock_pro_license_status' pour préserver la licence
            ];
            foreach ($pro_options as $option) {
                delete_option($option);
            }

            // Déprogrammer le cron de synchro Zelty.
            wp_clear_scheduled_hook('orderstock_pro_zelty_daily_sync');
        }

        // Suppression des fichiers PDF temporaires
        $upload_dir = wp_upload_dir()['basedir'] . '/tulipwork_orderstock/';
        if (file_exists($upload_dir)) {
            $files = glob($upload_dir . '*.pdf');
            foreach ($files as $file) {
                if (is_file($file)) {
                    wp_delete_file($file);
                }
            }
            @rmdir($upload_dir);
        }

        // Suppression des CPTs (plugin gratuit)
        $free_post_types = ['tulipwork_product', 'tulipwork_supplier', 'tulipwork_order'];
        foreach ($free_post_types as $post_type) {
            $posts = get_posts([
                'post_type' => $post_type,
                'posts_per_page' => -1,
                'post_status' => 'any',
                'suppress_filters' => true,
            ]);
            foreach ($posts as $post) {
                wp_delete_post($post->ID, true);
            }
        }

        // Suppression des CPTs spécifiques à OrderStock Pro si Pro est actif ou full_cleanup
        if ($is_pro_active || $full_cleanup) {
            $pro_post_types = ['tulipwork_store', 'tulipwork_inventory', 'tulipwork_waste'];
            foreach ($pro_post_types as $post_type) {
                $posts = get_posts([
                    'post_type' => $post_type,
                    'posts_per_page' => -1,
                    'post_status' => 'any',
                    'suppress_filters' => true,
                ]);
                foreach ($posts as $post) {
                    wp_delete_post($post->ID, true);
                }
            }
        }

        // Suppression des termes de taxonomie
        $terms = get_terms([
            'taxonomy' => 'tulipwork_prod_cat',
            'hide_empty' => false,
            'fields' => 'ids',
        ]);
        if (!is_wp_error($terms)) {
            foreach ($terms as $term_id) {
                wp_delete_term($term_id, 'tulipwork_prod_cat');
            }
        }

        // Suppression explicite de la taxonomie
        unregister_taxonomy('tulipwork_prod_cat');

        // Nettoyage des métadonnées résiduelles pour tous les CPTs
        $all_post_types = array_merge($free_post_types, ['tulipwork_store', 'tulipwork_inventory', 'tulipwork_waste']);
        foreach ($all_post_types as $post_type) {
            $result = $wpdb->query(
                $wpdb->prepare(
                    "DELETE pm FROM {$wpdb->postmeta} pm
                    LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
                    WHERE p.post_type = %s AND p.ID IS NULL",
                    $post_type
                )
            );
            if (false === $result) {
                error_log("OrderStock Cleanup: Failed to delete orphaned postmeta for post_type $post_type on blog $blog_id");
            }
        }

        // Gestion de la table personnalisée (OrderStock Pro) si Pro est actif ou full_cleanup
        if ($is_pro_active || $full_cleanup) {
            $table_name = $wpdb->prefix . 'tulipwork_stocks';
            if ($preserve_structure) {
                // Vider la table au lieu de la supprimer
                $result = $wpdb->query("TRUNCATE TABLE $table_name");
                if (false === $result) {
                    error_log("OrderStock Cleanup: Failed to truncate table $table_name on blog $blog_id: " . $wpdb->last_error);
                } else {
                    error_log("OrderStock Cleanup: Successfully truncated table $table_name on blog $blog_id");
                }
            } else {
                // Supprimer la table complètement
                $wpdb->query("DROP TABLE IF EXISTS $table_name");
                error_log("OrderStock Cleanup: Dropped table $table_name on blog $blog_id");
            }

            // Tables Zelty (recettes BOM + historique de disponibilité)
            foreach ([$wpdb->prefix . 'tulipwork_recipes', $wpdb->prefix . 'tulipwork_zelty_availability'] as $zelty_table) {
                if ($preserve_structure) {
                    $wpdb->query("TRUNCATE TABLE $zelty_table");
                } else {
                    $wpdb->query("DROP TABLE IF EXISTS $zelty_table");
                    error_log("OrderStock Cleanup: Dropped table $zelty_table on blog $blog_id");
                }
            }
        }

        // Suppression des métadonnées utilisateur spécifiques à OrderStock Pro (User Management)
        if ($is_pro_active || $full_cleanup) {
            $result = $wpdb->query(
                "DELETE FROM {$wpdb->usermeta} 
                WHERE meta_key = '_orderstock_assigned_stores'"
            );
            if (false === $result) {
                error_log("OrderStock Cleanup: Failed to delete _orderstock_assigned_stores usermeta on blog $blog_id");
            }
        }

        // Suppression des transients liés aux rapports (Reports)
        if ($is_pro_active || $full_cleanup) {
            $transients = $wpdb->get_col(
                "SELECT option_name
                FROM {$wpdb->options}
                WHERE option_name LIKE '_transient_orderstock_reports_%'"
            );
            foreach ($transients as $transient) {
                $transient_name = str_replace('_transient_', '', $transient);
                delete_transient($transient_name);
            }
        }

        // Suppression des transients du cache catalogue Zelty
        if ($is_pro_active || $full_cleanup) {
            $zelty_transients = $wpdb->get_col(
                "SELECT option_name
                FROM {$wpdb->options}
                WHERE option_name LIKE '_transient_orderstock_pro_zelty_dishes_%'
                   OR option_name LIKE '_transient_timeout_orderstock_pro_zelty_dishes_%'
                   OR option_name LIKE '_transient_orderstock_pro_zelty_options_%'
                   OR option_name LIKE '_transient_timeout_orderstock_pro_zelty_options_%'
                   OR option_name LIKE '_transient_orderstock_pro_zelty_menus_%'
                   OR option_name LIKE '_transient_timeout_orderstock_pro_zelty_menus_%'"
            );
            foreach ($zelty_transients as $transient) {
                $transient_name = preg_replace('/^_transient_(timeout_)?/', '', $transient);
                delete_transient($transient_name);
            }
        }

        // Suppression des capacités personnalisées (plugin gratuit)
        $capabilities = [
            'tulipwork_orderstock_access',
            'tulipwork_orderstock_access_stock',
            'tulipwork_orderstock_access_orders',
            'tulipwork_orderstock_access_products',
            'tulipwork_orderstock_access_suppliers',
            'tulipwork_orderstock_access_settings',
            'tulipwork_orderstock_access_inventories',
            'tulipwork_orderstock_access_history',
            'tulipwork_orderstock_access_reports',
            'tulipwork_orderstock_access_import_export',
            'tulipwork_orderstock_access_zelty',
            'tulipwork_orderstock_access_users',
        ];
        $roles = wp_roles();
        foreach ($roles->role_objects as $role) {
            foreach ($capabilities as $cap) {
                $role->remove_cap($cap);
            }
        }

        // Restaurer les capacités de base pour l'utilisateur actuel ou les administrateurs
        $current_user = wp_get_current_user();
        if ($current_user->ID) {
            $admin_role = get_role('administrator');
            if ($admin_role && in_array('administrator', $current_user->roles)) {
                // Restaurer les capacités de base pour les administrateurs
                $admin_role->add_cap('tulipwork_orderstock_access');
                $admin_role->add_cap('tulipwork_orderstock_access_stock');
                $admin_role->add_cap('tulipwork_orderstock_access_orders');
                $admin_role->add_cap('tulipwork_orderstock_access_products');
                $admin_role->add_cap('tulipwork_orderstock_access_suppliers');
                $admin_role->add_cap('tulipwork_orderstock_access_settings');
                error_log("OrderStock Cleanup: Restored base capabilities for administrator role on blog $blog_id");
            }
        }

        // Suppression des rôles personnalisés (OrderStock Pro) si Pro est actif ou full_cleanup
        if ($is_pro_active || $full_cleanup) {
            $pro_roles = [
                'orderstock_stock_manager',
                'orderstock_order_manager',
                'orderstock_kitchen_manager',
                'orderstock_full_manager',
                'tulipworkmember',
            ];
            foreach ($pro_roles as $role) {
                if (get_role($role)) {
                    remove_role($role);
                }
            }
        }
    }

    // Restaurer le blog courant en multisite
    if (is_multisite()) {
        restore_current_blog();
    }
}