<?php

/**
 * Levels and Badges Functions
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Get available badge icons
 */
function spar_get_badge_icons() {
    $icons = [
        '🥉' => esc_html__( 'Bronze Medal', 'simple-points-and-rewards' ),
        '🥈' => esc_html__( 'Silver Medal', 'simple-points-and-rewards' ),
        '🥇' => esc_html__( 'Gold Medal', 'simple-points-and-rewards' ),
        '⭐'  => esc_html__( 'Star', 'simple-points-and-rewards' ),
        '🌟' => esc_html__( 'Glowing Star', 'simple-points-and-rewards' ),
        '✨'  => esc_html__( 'Sparkles', 'simple-points-and-rewards' ),
        '🏆' => esc_html__( 'Trophy', 'simple-points-and-rewards' ),
        '👑' => esc_html__( 'Crown', 'simple-points-and-rewards' ),
        '💎' => esc_html__( 'Diamond', 'simple-points-and-rewards' ),
        '🎯' => esc_html__( 'Target', 'simple-points-and-rewards' ),
        '🚀' => esc_html__( 'Rocket', 'simple-points-and-rewards' ),
        '⚡'  => esc_html__( 'Lightning', 'simple-points-and-rewards' ),
        '🔥' => esc_html__( 'Fire', 'simple-points-and-rewards' ),
        '💫' => esc_html__( 'Shooting Star', 'simple-points-and-rewards' ),
        '🌈' => esc_html__( 'Rainbow', 'simple-points-and-rewards' ),
    ];
    /**
     * Filter the available badge icons for levels.
     *
     * @param array $icons Array of emoji/icon => label.
     */
    return apply_filters( 'spar_badge_icons', $icons );
}

/**
 * Normalize badge data for a level or starter configuration.
 *
 * @param string $badge_icon Emoji or preset badge icon.
 * @param string $badge_url  Optional custom badge image URL.
 * @param string $badge_type Badge type indicator (preset|custom_url|custom_text).
 * @param string $badge_text Optional custom text badge.
 *
 * @return array Normalized badge data.
 */
function spar_normalize_badge_fields(
    $badge_icon = '',
    $badge_url = '',
    $badge_type = '',
    $badge_text = ''
) {
    $allowed_types = array('preset', 'custom_url', 'custom_text');
    if ( !in_array( $badge_type, $allowed_types, true ) ) {
        $badge_type = '';
    }
    if ( '' === $badge_type ) {
        if ( '' !== $badge_url ) {
            $badge_type = 'custom_url';
        } elseif ( '' !== $badge_text ) {
            $badge_type = 'custom_text';
        } elseif ( '' !== $badge_icon ) {
            $badge_type = 'preset';
        } else {
            $badge_type = 'preset';
        }
    }
    if ( 'custom_url' === $badge_type ) {
        $badge_icon = '';
        $badge_text = '';
    } elseif ( 'custom_text' === $badge_type ) {
        if ( '' === $badge_text && '' !== $badge_icon ) {
            $badge_text = $badge_icon;
        }
        $badge_icon = '';
        $badge_url = '';
    } else {
        $badge_type = 'preset';
        if ( '' === $badge_icon && '' !== $badge_text ) {
            $badge_icon = $badge_text;
        }
        $badge_url = '';
        $badge_text = '';
    }
    return array(
        'badge_type' => $badge_type,
        'badge_icon' => $badge_icon,
        'badge_url'  => $badge_url,
        'badge_text' => $badge_text,
    );
}

/**
 * Render the badge markup for a level based on normalized badge data.
 *
 * @param array $level Level data containing badge fields.
 * @param array $args  Rendering overrides.
 *
 * @return string HTML markup for the badge icon/image.
 */
function spar_get_level_badge_markup(  $level, $args = array()  ) {
    $defaults = array(
        'icon_class'  => 'spar-level-badge-icon',
        'image_class' => 'spar-level-badge-img',
    );
    $args = wp_parse_args( $args, $defaults );
    $badge_type = $level['badge_type'] ?? '';
    if ( 'custom_url' === $badge_type && !empty( $level['badge_url'] ) ) {
        return '<img src="' . esc_url( $level['badge_url'] ) . '" alt="' . esc_attr( $level['name'] ?? '' ) . '" class="' . esc_attr( $args['image_class'] ) . '" />';
    }
    if ( 'custom_text' === $badge_type && !empty( $level['badge_text'] ) ) {
        return '<span class="' . esc_attr( $args['icon_class'] ) . '">' . esc_html( $level['badge_text'] ) . '</span>';
    }
    if ( !empty( $level['badge_url'] ) ) {
        return '<img src="' . esc_url( $level['badge_url'] ) . '" alt="' . esc_attr( $level['name'] ?? '' ) . '" class="' . esc_attr( $args['image_class'] ) . '" />';
    }
    if ( !empty( $level['badge_icon'] ) ) {
        return '<span class="' . esc_attr( $args['icon_class'] ) . '">' . esc_html( $level['badge_icon'] ) . '</span>';
    }
    if ( !empty( $level['badge_text'] ) ) {
        return '<span class="' . esc_attr( $args['icon_class'] ) . '">' . esc_html( $level['badge_text'] ) . '</span>';
    }
    return '';
}

/**
 * Generate a unique level ID
 */
function spar_generate_level_id() {
    return 'level_' . wp_generate_password( 8, false, false );
}

/**
 * Get all configured levels including Level 0 if enabled
 */
function spar_get_all_levels() {
    $options = get_option( 'spar_options', [] );
    $levels_enabled = !empty( $options['levels_enabled'] );
    $configured_levels = $options['levels'] ?? [];
    if ( !$levels_enabled ) {
        return [];
    }
    $all_levels = [];
    // Always add Level 0 (Starter) when levels are enabled
    $earn_options = $options['earn'] ?? [];
    $order_options = $earn_options['order'] ?? [];
    $referral_options = $earn_options['referral'] ?? [];
    $starter_name = $options['levels_starter_name'] ?? esc_html__( 'Starter', 'simple-points-and-rewards' );
    $starter_badge_data = spar_normalize_badge_fields(
        $options['levels_starter_badge_icon'] ?? '🌱',
        $options['levels_starter_badge_url'] ?? '',
        $options['levels_starter_badge_type'] ?? '',
        $options['levels_starter_badge_text'] ?? ''
    );
    // Derive base earning phrasing from split fields
    $pp_points = ( isset( $order_options['points_per_points'] ) ? (float) $order_options['points_per_points'] : (float) ($order_options['points_per'] ?? 5) );
    $pp_amount = ( isset( $order_options['points_per_amount'] ) && (float) $order_options['points_per_amount'] > 0 ? (float) $order_options['points_per_amount'] : 1.0 );
    $currency_code = ( function_exists( 'get_woocommerce_currency' ) ? get_woocommerce_currency() : (( defined( 'WC_VERSION' ) ? get_option( 'woocommerce_currency' ) : 'USD' )) );
    $currency_symbol = ( function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol( $currency_code ) : '$' );
    $all_levels[] = [
        'id'                     => 'level_0',
        'name'                   => $starter_name,
        'required_points'        => 0,
        'badge_type'             => $starter_badge_data['badge_type'],
        'badge_icon'             => $starter_badge_data['badge_icon'],
        'badge_url'              => $starter_badge_data['badge_url'],
        'badge_text'             => $starter_badge_data['badge_text'],
        'points_multiplier'      => 1.0,
        'is_default'             => true,
        'level_up_email_enabled' => false,
        'level_up_email_subject' => '',
        'level_up_email_body'    => '',
        'description'            => sprintf(
            /* translators: 1: points amount, 2: currency symbol, 3: amount */
            esc_html__( '%1$s points per %2$s%3$s spent', 'simple-points-and-rewards' ),
            number_format_i18n( (float) $pp_points, ( floor( $pp_points ) == $pp_points ? 0 : 1 ) ),
            $currency_symbol,
            spar_format_currency_amount( $pp_amount )
        ),
        'benefits'               => [
            /* translators: 1: points amount, 2: currency symbol, 3: amount */
            sprintf(
                esc_html__( '%1$s points per %2$s%3$s spent', 'simple-points-and-rewards' ),
                number_format_i18n( (float) $pp_points, ( floor( $pp_points ) == $pp_points ? 0 : 1 ) ),
                $currency_symbol,
                spar_format_currency_amount( $pp_amount )
            ),
            /* translators: %s: points earned per referral */
            sprintf( esc_html__( '%s points for each referral', 'simple-points-and-rewards' ), $referral_options['points'] ?? 100 ),
            esc_html__( 'No extra benefits', 'simple-points-and-rewards' ),
        ],
    ];
    // Add configured levels
    foreach ( $configured_levels as $level ) {
        // Skip incomplete levels (drafts)
        if ( empty( $level['name'] ) || (int) ($level['required_points'] ?? 0) <= 0 ) {
            continue;
        }
        // Ensure points_multiplier is properly set
        if ( !isset( $level['points_multiplier'] ) ) {
            $level['points_multiplier'] = 1.0;
        }
        $badge_data = spar_normalize_badge_fields(
            $level['badge_icon'] ?? '',
            $level['badge_url'] ?? '',
            $level['badge_type'] ?? '',
            $level['badge_text'] ?? ''
        );
        $level = array_merge( $level, $badge_data );
        $level['level_up_email_enabled'] = !empty( $level['level_up_email_enabled'] );
        $level['level_up_email_subject'] = ( isset( $level['level_up_email_subject'] ) ? (string) $level['level_up_email_subject'] : '' );
        $level['level_up_email_body'] = ( isset( $level['level_up_email_body'] ) ? (string) $level['level_up_email_body'] : '' );
        $level['is_default'] = false;
        $level['description'] = sprintf( 
            /* translators: %s: points multiplier (e.g., 1.5) */
            esc_html__( '%sx points multiplier', 'simple-points-and-rewards' ),
            spar_format_multiplier( $level['points_multiplier'] )
         );
        // Add all benefits for this level.
        $benefits = [];
        $benefits[] = sprintf( 
            /* translators: %s: points multiplier (e.g., 1.5) */
            esc_html__( '%sx points multiplier', 'simple-points-and-rewards' ),
            spar_format_multiplier( $level['points_multiplier'] )
         );
        // Add custom benefits if any exist
        if ( !empty( $level['custom_benefits'] ) ) {
            $custom_benefits_lines = explode( "\n", trim( $level['custom_benefits'] ) );
            foreach ( $custom_benefits_lines as $benefit_line ) {
                $benefit_line = trim( $benefit_line );
                if ( !empty( $benefit_line ) ) {
                    $benefits[] = $benefit_line;
                }
            }
        }
        $level['benefits'] = $benefits;
        $all_levels[] = $level;
    }
    // Sort by required points
    usort( $all_levels, function ( $a, $b ) {
        return $a['required_points'] - $b['required_points'];
    } );
    /**
     * Filter the array of all levels prior to use.
     *
     * @param array $all_levels Assembled levels including Level 0.
     * @param array $options    Plugin options array.
     */
    return apply_filters( 'spar_all_levels', $all_levels, $options );
}

/**
 * Get user's total points earned (lifetime, not current balance).
 *
 * Source of truth is user meta ('_spar_total_earned_points').
 * If missing, lazily backfill from the activity log (sum of 'add' events),
 * save to meta, and return the value.
 */
function spar_get_user_total_points_earned(  $user_id  ) {
    $user_id = absint( $user_id );
    if ( !$user_id ) {
        return 0;
    }
    // Read from user meta first
    $meta_key = '_spar_total_earned_points';
    $total_earned = get_user_meta( $user_id, $meta_key, true );
    // If not set, backfill from logs once and persist
    if ( '' === $total_earned || null === $total_earned ) {
        global $wpdb;
        $table = $wpdb->prefix . 'spar_points_logs';
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $computed = $wpdb->get_var( $wpdb->prepare(
            'SELECT COALESCE(SUM(points),0) FROM %i WHERE user_id = %d AND type = %s',
            $table,
            $user_id,
            'add'
        ) );
        $computed = absint( $computed );
        update_user_meta( $user_id, $meta_key, $computed );
        return $computed;
    }
    return absint( $total_earned );
}

/**
 * Get the points value used for level calculations.
 *
 * Returns either the total lifetime points earned or the current available
 * balance depending on the `levels_points_type` setting.
 *
 * @param int $user_id User ID.
 * @return int Points value used for level requirements.
 */
function spar_get_user_level_points(  $user_id  ) {
    $defaults = spar_settings_default();
    $options = get_option( 'spar_options', $defaults );
    $type = ( isset( $options['levels_points_type'] ) ? $options['levels_points_type'] : 'total_earned' );
    if ( 'available_balance' === $type ) {
        return spar_get_user_points( $user_id );
    }
    return spar_get_user_total_points_earned( $user_id );
}

/**
 * Get user's current level (based on level points type setting)
 */
function spar_get_user_level(  $user_id  ) {
    $total_points_earned = spar_get_user_level_points( $user_id );
    $all_levels = spar_get_all_levels();
    if ( empty( $all_levels ) ) {
        return null;
    }
    $current_level = $all_levels[0];
    // Start with lowest level
    $count = 0;
    foreach ( $all_levels as $level ) {
        $count++;
        if ( $count > 2 ) {
            break;
        }
        if ( $total_points_earned >= $level['required_points'] ) {
            $current_level = $level;
        } else {
            break;
        }
    }
    /**
     * Filter the resolved current level for a user.
     *
     * @param array|null $current_level Current level array or null.
     * @param int        $user_id       User ID.
     * @param array      $all_levels    All levels array.
     */
    return apply_filters(
        'spar_user_level',
        $current_level,
        (int) $user_id,
        $all_levels
    );
}

/**
 * Get user's next level (based on level points type setting)
 */
function spar_get_user_next_level(  $user_id  ) {
    $total_points_earned = spar_get_user_level_points( $user_id );
    $all_levels = spar_get_all_levels();
    if ( empty( $all_levels ) ) {
        return null;
    }
    $count = 0;
    foreach ( $all_levels as $level ) {
        $count++;
        if ( $count > 2 ) {
            break;
        }
        if ( $total_points_earned < $level['required_points'] ) {
            return $level;
        }
    }
    $next = null;
    // User is at max level
    /**
     * Filter the next level for a user (or null if max level).
     *
     * @param array|null $next       Next level array or null.
     * @param int        $user_id    User ID.
     * @param array      $all_levels All levels array.
     */
    return apply_filters(
        'spar_user_next_level',
        $next,
        (int) $user_id,
        $all_levels
    );
}

/**
 * Get level progress percentage (based on level points type setting)
 */
function spar_get_level_progress(  $user_id  ) {
    $current_level = spar_get_user_level( $user_id );
    $next_level = spar_get_user_next_level( $user_id );
    $total_points_earned = spar_get_user_level_points( $user_id );
    if ( !$current_level || !$next_level ) {
        return 100;
        // Max level reached
    }
    $current_required = $current_level['required_points'];
    $next_required = $next_level['required_points'];
    $points_in_level = $total_points_earned - $current_required;
    $points_needed_for_next = $next_required - $current_required;
    if ( $points_needed_for_next <= 0 ) {
        return 100;
    }
    $progress = min( 100, $points_in_level / $points_needed_for_next * 100 );
    /**
     * Filter the computed level progress percentage for a user.
     *
     * @param float     $progress     Percentage 0-100.
     * @param int       $user_id      User ID.
     * @param array     $current_level Current level array.
     * @param array     $next_level    Next level array.
     */
    return (float) apply_filters(
        'spar_level_progress',
        $progress,
        (int) $user_id,
        $current_level,
        $next_level
    );
}

/**
 * Display user level badge
 */
function spar_display_user_level_badge(  $user_id, $show_name = true  ) {
    $level = spar_get_user_level( $user_id );
    if ( !$level ) {
        return '';
    }
    $normalized = spar_normalize_badge_fields(
        $level['badge_icon'] ?? '',
        $level['badge_url'] ?? '',
        $level['badge_type'] ?? '',
        $level['badge_text'] ?? ''
    );
    $level = array_merge( $level, $normalized );
    $badge_markup = spar_get_level_badge_markup( $level );
    if ( '' === $badge_markup ) {
        if ( !$show_name ) {
            return '';
        }
        return '<span class="spar-user-level-badge"><span class="spar-level-name">' . esc_html( $level['name'] ?? '' ) . '</span></span>';
    }
    if ( $show_name && !empty( $level['name'] ) ) {
        $badge_markup .= ' <span class="spar-level-name">' . esc_html( $level['name'] ) . '</span>';
    }
    return '<span class="spar-user-level-badge">' . $badge_markup . '</span>';
}

/**
 * Display level progress bar (based on level points type setting)
 */
function spar_display_level_progress_bar(  $user_id  ) {
    $current_level = spar_get_user_level( $user_id );
    $next_level = spar_get_user_next_level( $user_id );
    $progress = spar_get_level_progress( $user_id );
    $total_points_earned = spar_get_user_level_points( $user_id );
    if ( !$current_level ) {
        return '';
    }
    $html = '<div class="spar-level-progress-container">';
    if ( $next_level ) {
        // Progress bar
        $points_needed = $next_level['required_points'] - $total_points_earned;
        $html .= '<div class="spar-level-progress-bar">';
        $html .= '<div class="spar-level-progress-fill" style="width: ' . esc_attr( $progress ) . '%;"></div>';
        $html .= '</div>';
        // Next level info
        $html .= '<div class="spar-level-next">';
        $html .= '<span>' . sprintf( 
            /* translators: %s: next level name */
            esc_html__( 'Next: %1$s', 'simple-points-and-rewards' ),
            esc_html( $next_level['name'] )
         ) . '</span>';
        $html .= '<span>' . sprintf( 
            /* translators: %s: points needed to reach next level */
            esc_html__( '%1$s points needed', 'simple-points-and-rewards' ),
            number_format_i18n( (int) $points_needed )
         ) . '</span>';
        $html .= '</div>';
    } else {
        $html .= '<div class="spar-level-max">';
        $html .= '🎉 ' . esc_html__( 'Maximum level reached!', 'simple-points-and-rewards' );
        $html .= '</div>';
    }
    $html .= '</div>';
    return $html;
}

/**
 * Get the earn type labels used for per-earn-type multiplier settings.
 *
 * @return array Associative array of earn_type_key => label.
 */
function spar_get_earn_type_labels() {
    $defaults = spar_settings_default();
    $options = get_option( 'spar_options', $defaults );
    $options = array_merge( $defaults, $options );
    $earn = $options['earn'] ?? [];
    $labels = [
        'order'       => $earn['order']['name'] ?? esc_html__( 'Place an Order', 'simple-points-and-rewards' ),
        'order_fixed' => $earn['order_fixed']['name'] ?? esc_html__( 'Points for Orders', 'simple-points-and-rewards' ),
        'signup'      => $earn['signup']['name'] ?? esc_html__( 'Signup Bonus', 'simple-points-and-rewards' ),
        'referral'    => $earn['referral']['name'] ?? esc_html__( 'Referral Bonus', 'simple-points-and-rewards' ),
        'review'      => $earn['review']['name'] ?? esc_html__( 'Write a Review', 'simple-points-and-rewards' ),
        'birthday'    => $earn['birthday']['name'] ?? esc_html__( 'Birthday Bonus', 'simple-points-and-rewards' ),
        'daily_login' => $earn['daily_login']['name'] ?? esc_html__( 'Daily Login Bonus', 'simple-points-and-rewards' ),
        'first_order' => $earn['first_order']['name'] ?? esc_html__( 'First Order Bonus', 'simple-points-and-rewards' ),
        'nth_order'   => $earn['nth_order']['name'] ?? esc_html__( 'Bonus after X Orders', 'simple-points-and-rewards' ),
    ];
    return apply_filters( 'spar_earn_type_labels', $labels );
}

/**
 * Get points multiplier for user's current level.
 *
 * @param int    $user_id   User ID.
 * @param string $earn_type Optional earn type key (e.g. 'order', 'signup'). When provided and
 *                          the level has custom per-earn-type multipliers, returns the specific
 *                          multiplier for that type.
 * @return float Multiplier value.
 */
function spar_get_user_points_multiplier(  $user_id, $earn_type = ''  ) {
    $level = spar_get_user_level( $user_id );
    if ( !$level ) {
        return 1.0;
    }
    $multiplier = floatval( $level['points_multiplier'] ?? 1.0 );
    $multiplier = max( 0.0, $multiplier );
    // Check for per-earn-type override (PRO only).
    if ( function_exists( 'spar_fs' ) && spar_fs()->can_use_premium_code__premium_only() ) {
        if ( '' !== $earn_type && !empty( $level['custom_multipliers_enabled'] ) && !empty( $level['earn_type_multipliers'] ) && is_array( $level['earn_type_multipliers'] ) ) {
            if ( isset( $level['earn_type_multipliers'][$earn_type] ) && '' !== $level['earn_type_multipliers'][$earn_type] ) {
                $multiplier = max( 0.0, floatval( $level['earn_type_multipliers'][$earn_type] ) );
            }
        }
    }
    /**
     * Filter the points multiplier for a user's current level.
     *
     * @param float  $multiplier Multiplier (>=0.0).
     * @param int    $user_id    User ID.
     * @param array  $level      Current level array.
     * @param string $earn_type  Earn type key or empty string.
     */
    return (float) apply_filters(
        'spar_user_points_multiplier',
        $multiplier,
        (int) $user_id,
        $level,
        $earn_type
    );
}

/**
 * Get referral points bonus for user's current level (deprecated - use multiplier instead)
 */
function spar_get_user_referral_bonus(  $user_id  ) {
    // This function is kept for backward compatibility but now returns 0
    // Use spar_get_user_points_multiplier() instead
    return 0;
}
