<?php

namespace CouponsPlus\App\Conditions\BuiltIn\Conditions;

use BadMethodCallException;
use InvalidArgumentException;
use CouponsPlus\App\Conditions\Condition;
use CouponsPlus\Original\Characters\StringManager;
use CouponsPlus\Original\Collections\Collection;
use CouponsPlus\Original\Collections\Mapper\Types;

#[\AllowDynamicProperties]
Class ShippingMethod extends Condition
{
    const TYPE = 'ShippingMethod';
    
    static public function getName() : string
    {
        return __('Shipping Methods', 'coupons-plus-for-woocommerce');
    }

    static public function getDescription() : string
    {
        return '';
    }
    
    static public function getUseCases(): Collection
    {
        return new Collection([
            __('Restrict offers to specific methods.', 'coupons-plus-for-woocommerce'),
            __('Exclude offers from specific methods.', 'coupons-plus-for-woocommerce'),
            __('Apply different discounts based on the selected method (EG: Flat Rate -> 50% OFF, Local Pickup -> 10% OFF, ...).', 'coupons-plus-for-woocommerce'),
        ]);  
    } 

    public static function getOptions() : Collection
    {
        return new Collection([
            'ids' => Types::COLLECTION, // the method ids: flat_rate, free_shipping, etc
            'inclusionType' => Types::STRING()->withDefault('allowed')
                                              ->allowed([
                                                __('Eligible', 'coupons-plus-for-woocommerce') => 'allowed',
                                                __('Not Eligible', 'coupons-plus-for-woocommerce') => 'forbidden'
                                               ]),
        ]);
    }
    
    /** @noinspection PhpUnhandledExceptionInspection */
    protected function test() : bool
    {
        (boolean)$selectedMethodIdsContain = $this->options->ids->map([StringManager::class, 'create'])->find(function (StringManager $id) : bool {
            if ($id->contains(':')) {
                return $this->matchesSelectedMethodFromSpecificZone($id);
            }

            return $this->matchesSelectedMethodFromAnyZone($id);
        }) !== null;
/*        (boolean) $selectedMethodIdsContain = $this->options->ids->containEither($selectedMethodIds->asArray());*/

        return $this->options->inclusionType->is('allowed')? $selectedMethodIdsContain : !$selectedMethodIdsContain;
    }

    /** @noinspection PhpUnhandledExceptionInspection */
    protected function matchesSelectedMethodFromSpecificZone(StringManager $id) : bool
    {
        return $this->getAllSelectedMethods(false)->contain($id->get());
    }

    /** @noinspection PhpUnhandledExceptionInspection */
    private function matchesSelectedMethodFromAnyZone(StringManager $id)
    {
        return $this->getAllSelectedMethods(true)->contain($id->get());
    }


    /**
     * @throws InvalidArgumentException
     * @throws BadMethodCallException
     */
    protected function getAllSelectedMethods(bool $asGlobal = false): Collection
    {
        (object)$methods = new Collection(WC()->session->get('chosen_shipping_methods') ?: []);

        if ($asGlobal) {
            return $methods->map(function (string $methodIdWithInstanceId): string {
                return StringManager::create($methodIdWithInstanceId)->replaceRegEx('/:\d+$/', '')->get();
            });
        }

        return $methods;
    }
}