<?php

declare(strict_types=1);

namespace ACA\WC\Editing\StorageModel\Product;

use ACA\WC\Editing\EditValue;
use ACA\WC\Helper\Price\Rounding;
use WC_Product;
use WP_Error;

class Price
{

    protected WC_Product $product;

    protected EditValue\Product\Price $value;

    protected Rounding $rounding;

    public function __construct(WC_Product $product, EditValue\Product\Price $value)
    {
        $this->product = $product;
        $this->value = $value;
        $this->rounding = new Rounding();
    }

    /**
     * @return int|WP_Error
     */
    public function save()
    {
        $price = $this->get_calculated_price();

        if ($price < 0) {
            return new WP_Error('invalid-price', __('Price can not lower than zero.', 'codepress-admin-columns'));
        }

        if ($this->value->is_rounded() || 'flat' !== $this->value->get_price_type()) {
            $price = $this->round_price($price);
        }

        $this->product->set_regular_price($price);

        return $this->product->save();
    }

    protected function round_price(float $price): float
    {
        switch ($this->value->get_rounding_type()) {
            case 'roundup':
                return $this->rounding->up($price, $this->value->get_rounding_decimals());

            case 'rounddown':
                return $this->rounding->down($price, $this->value->get_rounding_decimals());

            default:
                return round($price, apply_filters('acp/wc/editing/price/rounding_decimals', 2));
        }
    }

    protected function get_calculated_price(): float
    {
        switch ($this->value->get_price_type()) {
            case 'increase_percentage':
                return $this->increase_price_by_percentage($this->get_price(), $this->value->get_percentage());

            case 'decrease_percentage':
                return $this->decrease_price_by_percentage($this->get_price(), $this->value->get_percentage());

            case 'increase_price':
                return ($this->get_price() + (float)$this->value->get_price());

            case 'decrease_price':
                return ($this->get_price() - (float)$this->value->get_price());

            default:
                return (float)$this->value->get_price();
        }
    }

    protected function increase_price_by_percentage(float $price, float $percentage): float
    {
        return $price + (($price / 100) * $percentage);
    }

    protected function decrease_price_by_percentage(float $price, float $percentage): float
    {
        return $price - (($price / 100) * $percentage);
    }

    protected function get_price(): float
    {
        return (float)$this->product->get_regular_price();
    }

}