<?php

namespace CouponsPlus\App\Offers\BuiltIn;

use CouponsPlus\App\Conditions\ItemsSet;
use CouponsPlus\App\Offers\CouponShippingDiscountAmount;
use CouponsPlus\App\Offers\Offer;
use CouponsPlus\App\Helpers\Currency;
use CouponsPlus\Original\Characters\StringManager;
use CouponsPlus\Original\Collections\Collection;
use CouponsPlus\Original\Collections\Mapper\Types;
use CouponsPlus\Original\Environment\Env;
use Mattiasgeniar\Percentage\Percentage;
use WC_Shipping_Rate;
use CouponsPlus\App\Coupon\Tree\Finders\Sets\OfferItems;

#[\AllowDynamicProperties]
Class ShippingDiscount extends Offer
{
    const TYPE = 'ShippingDiscount';

    // test:
    // with two different offer types at once
    // $couponsWithThisOfferAlreadyApplied might use a 
    // [
    //  'ShippingDiscount' => ['coupon-code']
    // ]
    // in the parent class so as to avoid having a static property on each class
    // since we can have a static property on the main class because of late binding
    protected static $couponsWithThisOfferAlreadyApplied = [];

    public static function getName() : string
    {
        return __('Shipping Discount', 'coupons-plus-for-woocommerce');
    }

    public static function getDescription() : string
    {
        return __("Applies a discount to the cart's shipping total regardless of the shipping method selected.", 'coupons-plus-for-woocommerce');
    }

    public static function getOptions() : Collection
    {
        (string) $currencySymbol = (Currency::$currencies[get_woocommerce_currency()] ?? Currency::$currencies['USD'])['symbol'];

        return new Collection([
            'type' => Types::STRING()->withDefault('percentage')
                                    ->allowed([
                                        '% off' => 'percentage',
                                        "{$currencySymbol} off" => 'amount',
                                        "Final Price" => 'finalCost',
                                    ])->meta([
                                        'alternativeLabels' => [
                                            'percentage' => __('Percentage', 'coupons-plus-for-woocommerce'),
                                            'amount' => __('Amount', 'coupons-plus-for-woocommerce'),
                                            'finalCost' => ''
                                        ]
                ]),
            'amount' => Types::FLOAT
        ]);
    }

    public function apply(ItemsSet $itemsSet): void
    {
        if (in_array($this->coupon->get_code($context = 'edit'), static::$couponsWithThisOfferAlreadyApplied)) {
            return;
        }
        //
        // This one should be better to implement than the one we have now
        //
        //add_filter( 'woocommerce_package_rates', [$this, 'getUpdatedShippingWithDiscount'] );

        /**
         * Extremely important otherwise bugs will appear when changing locations!
         */
        \WC_Cache_Helper::get_transient_version( 'shipping', true );

        add_filter('woocommerce_shipping_method_add_rate_args', [$this, 'getShippingWithDiscount']);
        add_action('woocommerce_after_calculate_totals', [$this, 'unregisterEvent']);

        static::$couponsWithThisOfferAlreadyApplied[] = $this->coupon->get_code($context = 'edit');
    }

    public function getUpdatedShippingWithDiscount($rates)
    {        
        foreach( $rates as $rate_key => $rate ){
            // Check if the shipping method ID is UPS for example
            //if( ($rate->method_id == 'flexible_shipping_ups') ) {
                // Set cost to zero
                $originalCost = $rates[$rate_key]->cost;
                $cost = $originalCost;
                switch($this->options->type->get()) {
                    case 'percentage':
                        (float) $percentageAmount = $this->options->amount;
                        (float) $amountToDiscount = Percentage::of($percentageAmount, $cost);
                        $cost -= $amountToDiscount;
                    break;
                    case 'amount':
                        (float) $amountToDiscount = $this->options->amount;
                        (float) $discountedAmounut = $cost - $amountToDiscount;

                        $cost = StringManager::create((string) $discountedAmounut)->startsWith('-')? 0 : $discountedAmounut;
                    break;
                    case 'finalCost':
                        $cost = $this->options->amount;
                    break;
                }

                $rates[$rate_key]->cost = $cost;
            //} 
        }
        return $rates;        
    }

    public function getShippingWithDiscount(array $rateArguments) : array
    {
        // only apply once
        //var_dump('$this->rateIdsApplied', $this->rateIdsApplied, $rateArguments['id'], spl_object_hash($this));

        (float) $cost = (float) (is_array($rateArguments['cost'])? array_sum($rateArguments['cost']) : $rateArguments['cost']);

        $rateArguments['meta_data']['cp_original_cost'] = $cost;

        switch($this->options->type->get()) {
            case 'percentage':
                (float) $percentageAmount = $this->options->amount;
                (float) $amountToDiscount = Percentage::of($percentageAmount, $cost);
                $rateArguments['cost'] -= $amountToDiscount;
            break;
            case 'amount':
                (float) $amountToDiscount = $this->options->amount;
                (float) $discountedAmounut = $cost - $amountToDiscount;

                $rateArguments['cost'] = StringManager::create((string) $discountedAmounut)->startsWith('-')? 0 : $discountedAmounut;
            break;
            case 'finalCost':
                $rateArguments['cost'] = $this->options->amount;
            break;
        }

        //$this->registerDiscountedAmount($amountToDiscount);

        return $rateArguments;
    }

    protected function registerDiscountedAmount(float $amountToDiscount)
    {
        /*(object) $discountAmount = new CouponShippingDiscountAmount($this->coupon);

        $discountAmount->addAmount($this->options->amount);*/
    }
    
    public function unregisterEvent()
    {
        if (!is_admin()) {
            static::$couponsWithThisOfferAlreadyApplied = [];
        }

        remove_filter(
            'woocommerce_shipping_method_add_rate_args', 
            [$this, 'getShippingWithDiscount']
        );
        /*
        remove_filter(
            'woocommerce_package_rates', 
            [$this, 'getShippingDiscount']
        );*/
    }

    public static function getIconUrl() : string
    {
        return Env::directoryURI().'/storage/icons/offers/ShippingDiscount.svg';   
    }
}