<?php

namespace CouponsPlus\App\Offers;

use WC_Coupon;
use CouponsPlus\Original\Environment\Env;
use CouponsPlus\Original\Collections\Collection;

class DiscountState
{
    public static ?DiscountState $instance = null;
    /**
     * @var Collection
     */
    public static $hardLimitsReached = [
        //unique Discount key (NOT cart item key!)
    ];

    /**
     * @var Collection
     */
    public static $sumOfDiscountAmounts = [
        //'unique Discount key (NOT cart item key!)' => (float)
    ];

    /**
     * @var Collection
     */
    public static $sumOfCartItemDiscountAmounts = [
        //'cart item key' => (float)
    ];


    private Collection $discounts;


    /**
     * Unfortunately, we ain't got no dependency injection in this version of the framework so we have to use this
     */
    public static function getInstance(): DiscountState
    {
        if (static::$instance === null) {
            static::$instance = new DiscountState();
        }

        return static::$instance;
    }

    public static function getSessionDiscountKey() : string
    {
        return Env::getWithPrefix('cart_item_discounts');
    }

    protected function __construct()
    {
        $this->reset();
    }

    public function registerDiscount(CouponItemDiscountAmount $discount)
    {
        $this->discounts->push($discount);
    }

    public function setHardLimitReached(string $uniqueKey)
    {
        static::$hardLimitsReached->push($uniqueKey);
    }

    public function hasHardLimitBeenReached(string $uniqueKey): bool
    {
        return static::$hardLimitsReached->have($uniqueKey);
    }

    /**
     * This is for discounts by unique key (NOT cart item key!) usually an offer key
     */
    public function addToSumOfDiscounts(string $uniqueKey, float $amount)
    {
        if (!static::$sumOfDiscountAmounts->hasKey($uniqueKey)) {
            static::$sumOfDiscountAmounts->set($uniqueKey, 0.0);
        }

        static::$sumOfDiscountAmounts->set($uniqueKey, bcadd((string)$this->getSumOfDiscounts($uniqueKey), (string)$amount, 2));
    }

    /**
     * This is for discounts by cart item key
     */
    public function addToSumOfCartItemDiscounts(string $cartItemKey, float $amount)
    {
        if (!static::$sumOfCartItemDiscountAmounts->hasKey($cartItemKey)) {
            static::$sumOfCartItemDiscountAmounts->set($cartItemKey, 0.0);
        }

        static::$sumOfCartItemDiscountAmounts->set(
            $cartItemKey,
            bcadd((string)$this->getSumOfCartItemDiscounts($cartItemKey), (string) $amount, 2)
        );
    }
    public function getSumOfDiscounts(string $uniqueKey): float
    {
        return static::$sumOfDiscountAmounts->get($uniqueKey) ?? 0;
    }

    public function getSumOfCartItemDiscounts(string $cartItemKey): float
    {
        return static::$sumOfCartItemDiscountAmounts->get($cartItemKey) ?? 0;
    }

    public function saveCartData()
    {
        $WCSession = WC()->session;

        if (!$WCSession) {
            return;
        }

        $discountsData = [];
        // here saves the each item discounts to the cart state as meta data
        /** @var CouponItemDiscountAmount $discount */
        foreach ($this->discounts->asArray() as $discount) {
            $discountsData[$discount->getCartItemKey()] = [
                'coupon_code' => $discount->getClassicCoupon()->get_code($context = 'edit'),
                'amount' => $discount->getSumOfDiscountsForThisCartItem(),
                /*'quantity' => $discount->getNumberOfItemsAppliedTo(), // seems unreliable right now*/
            ];
        }

        $WCSession->set(static::getSessionDiscountKey(), $discountsData);
    }

    public function cartItemHasBeenDiscounted(string $key): bool
    {
        $WCSession = WC()->session;

        if (!$WCSession) {
            return false;
        }

        $discountsData = $WCSession->get(static::getSessionDiscountKey(), []);


        $itemIsInArray = isset($discountsData[$key]);

        $itemHasActiveCoupon = $itemIsInArray && WC()->cart->has_discount($discountsData[$key]['coupon_code']);

        return $itemIsInArray && $itemHasActiveCoupon;
    }

    public function getDiscountDataForCartItem($key) : ?array
    {
        $WCSession = WC()->session;

        if (!$WCSession) {
            return null;
        }

        $discountsData = $WCSession->get(static::getSessionDiscountKey(), []);

        return $discountsData[$key] ?? null;
    }

    public function resetCartData()
    {
        $WCSession = WC()->session;

        if (!$WCSession) {
            return;
        }

        $WCSession->set(static::getSessionDiscountKey(), []);
    }

    public function removeCartDataForCoupon(WC_Coupon $coupon)
    {
        $WCSession = WC()->session;

        if (!$WCSession) {
            return;
        }

        $discountsData = $WCSession->get(static::getSessionDiscountKey(), []);

        foreach ($discountsData as $cartItemKey => $data) {
            if ($data['coupon_code'] === $coupon->get_code($context = 'edit')) {
                unset($discountsData[$cartItemKey]);
            }
        }

        $WCSession->set(static::getSessionDiscountKey(), $discountsData);
    }

    public function reset()
    {
        static::$hardLimitsReached = new Collection([]);
        static::$sumOfDiscountAmounts = new Collection([]);
        static::$sumOfCartItemDiscountAmounts = new Collection([]);
        $this->discounts = new Collection([]);
        $this->resetCartData();
    }
}