<?php
/**
 * Bundle Discount Calculator Service
 * 
 * Calculates discounts for product bundles including:
 * - Percentage discounts
 * - Fixed amount discounts
 * - Tiered discounts based on bundle value
 *
 * @package BoostBot
 * @since 1.2.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class BoostBot_Bundle_Discount_Calculator {

    /**
     * Pricing settings
     *
     * @var array
     */
    private $settings;

    /**
     * Constructor
     *
     * @param array $settings Pricing settings
     */
    public function __construct( array $settings = array() ) {
        $this->settings = wp_parse_args( $settings, $this->get_default_settings() );
    }

    /**
     * Get default pricing settings
     *
     * @return array
     */
    private function get_default_settings(): array {
        return array(
            // Discount type: percent | fixed | tiered
            'discount_type'           => 'percent',
            'discount_percent'        => 10,
            'discount_fixed'          => 50,

            // Tiered discounts
            'discount_tiers'          => array(
                array( 'min_amount' => 0, 'max_amount' => 200, 'discount' => 5 ),
                array( 'min_amount' => 200, 'max_amount' => 500, 'discount' => 10 ),
                array( 'min_amount' => 500, 'max_amount' => 1000, 'discount' => 15 ),
                array( 'min_amount' => 1000, 'max_amount' => null, 'discount' => 20 ),
            ),

            // Limits
            'max_discount_amount'     => null,
            'min_order_for_discount'  => 0,

            // Display
            'show_savings'            => true,
            'show_original_prices'    => true,
            'show_per_product_savings' => false,

            // Rounding
            'round_prices'            => true,
            'round_to'                => 0,
        );
    }

    /**
     * Calculate bundle discount
     *
     * @param array $bundle Bundle data with products and totals
     * @return array Calculated pricing
     */
    public function calculate( array $bundle ): array {
        $original_total = floatval( $bundle['original_price'] ?? 0 );
        $current_total = floatval( $bundle['total_price'] ?? 0 );

        // If no products, return zeros
        if ( $current_total <= 0 ) {
            return array(
                'original_price'       => 0,
                'subtotal'             => 0,
                'discount_amount'      => 0,
                'discount_percent'     => 0,
                'total_price'          => 0,
                'total_savings'        => 0,
                'total_savings_percent' => 0,
            );
        }

        // Check minimum order for discount
        $min_for_discount = floatval( $this->settings['min_order_for_discount'] );
        if ( $current_total < $min_for_discount ) {
            // No discount applied
            return array(
                'original_price'       => $this->maybe_round( $original_total ),
                'subtotal'             => $this->maybe_round( $current_total ),
                'discount_amount'      => 0,
                'discount_percent'     => 0,
                'total_price'          => $this->maybe_round( $current_total ),
                'total_savings'        => $this->maybe_round( $original_total - $current_total ),
                'total_savings_percent' => $original_total > 0 
                    ? round( ( ( $original_total - $current_total ) / $original_total ) * 100, 1 )
                    : 0,
            );
        }

        // Calculate discount amount based on type
        $discount_amount = $this->calculate_discount_amount( $current_total );

        // Apply maximum discount cap
        $max_discount = $this->settings['max_discount_amount'];
        if ( $max_discount !== null && $discount_amount > floatval( $max_discount ) ) {
            $discount_amount = floatval( $max_discount );
        }

        // Calculate final total
        $final_total = $current_total - $discount_amount;
        $final_total = max( 0, $final_total ); // Ensure non-negative

        // Calculate savings
        $total_savings = $original_total - $final_total;

        return array(
            'original_price'        => $this->maybe_round( $original_total ),
            'subtotal'              => $this->maybe_round( $current_total ),
            'discount_amount'       => $this->maybe_round( $discount_amount ),
            'discount_percent'      => $current_total > 0
                ? round( ( $discount_amount / $current_total ) * 100, 1 )
                : 0,
            'total_price'           => $this->maybe_round( $final_total ),
            'total_savings'         => $this->maybe_round( $total_savings ),
            'total_savings_percent' => $original_total > 0
                ? round( ( $total_savings / $original_total ) * 100, 1 )
                : 0,
        );
    }

    /**
     * Calculate discount amount based on discount type
     *
     * @param float $amount Order amount
     * @return float Discount amount
     */
    private function calculate_discount_amount( float $amount ): float {
        switch ( $this->settings['discount_type'] ) {
            case 'fixed':
                return floatval( $this->settings['discount_fixed'] );

            case 'tiered':
                $rate = $this->get_tiered_discount_rate( $amount );
                return $amount * ( $rate / 100 );

            case 'percent':
            default:
                $rate = floatval( $this->settings['discount_percent'] );
                return $amount * ( $rate / 100 );
        }
    }

    /**
     * Get discount rate from tiers
     *
     * @param float $amount Order amount
     * @return float Discount percentage
     */
    private function get_tiered_discount_rate( float $amount ): float {
        $tiers = $this->settings['discount_tiers'] ?? array();

        if ( empty( $tiers ) ) {
            return 0;
        }

        foreach ( $tiers as $tier ) {
            $min = floatval( $tier['min_amount'] ?? 0 );
            $max = $tier['max_amount'] !== null ? floatval( $tier['max_amount'] ) : PHP_INT_MAX;

            if ( $amount >= $min && $amount < $max ) {
                return floatval( $tier['discount'] ?? 0 );
            }
        }

        // Return last tier if amount exceeds all tiers
        $last_tier = end( $tiers );
        return floatval( $last_tier['discount'] ?? 0 );
    }

    /**
     * Round price if setting is enabled
     *
     * @param float $price
     * @return float
     */
    private function maybe_round( float $price ): float {
        if ( ! $this->settings['round_prices'] ) {
            return $price;
        }

        $decimals = intval( $this->settings['round_to'] );
        return round( $price, $decimals );
    }

    /**
     * Get discount description for display
     *
     * @param float $amount Bundle amount (optional, for tiered)
     * @return string
     */
    public function get_discount_description( float $amount = 0 ): string {
        $symbol = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '₪';

        switch ( $this->settings['discount_type'] ) {
            case 'fixed':
                return sprintf( '%s%s הנחה', $symbol, number_format( $this->settings['discount_fixed'], 0 ) );

            case 'tiered':
                $rate = $this->get_tiered_discount_rate( $amount );
                return sprintf( '%s%% הנחה', $rate );

            case 'percent':
            default:
                return sprintf( '%s%% הנחה', $this->settings['discount_percent'] );
        }
    }

    /**
     * Check if discount applies to amount
     *
     * @param float $amount Bundle amount
     * @return bool
     */
    public function qualifies_for_discount( float $amount ): bool {
        $min = floatval( $this->settings['min_order_for_discount'] );
        return $amount >= $min;
    }

    /**
     * Get amount needed to qualify for discount
     *
     * @param float $current_amount Current bundle amount
     * @return float Amount needed to add (0 if already qualifies)
     */
    public function amount_to_qualify( float $current_amount ): float {
        $min = floatval( $this->settings['min_order_for_discount'] );
        
        if ( $current_amount >= $min ) {
            return 0;
        }

        return $min - $current_amount;
    }

    /**
     * Calculate per-product discounts
     *
     * @param array $products Products array
     * @param float $discount_amount Total discount
     * @return array Products with individual discounts
     */
    public function apply_per_product_discount( array $products, float $discount_amount ): array {
        if ( empty( $products ) || $discount_amount <= 0 ) {
            return $products;
        }

        $total_price = array_sum( array_column( $products, 'price' ) );

        if ( $total_price <= 0 ) {
            return $products;
        }

        return array_map( function( $product ) use ( $total_price, $discount_amount ) {
            $price = floatval( $product['price'] ?? 0 );
            $ratio = $price / $total_price;
            $product_discount = $discount_amount * $ratio;

            $product['discounted_price'] = $this->maybe_round( $price - $product_discount );
            $product['product_discount'] = $this->maybe_round( $product_discount );

            return $product;
        }, $products );
    }
}





