<?php

require_once __DIR__ . '/OrderProblemInterface.php';

class OrderProblemAvoir implements OrderProblemInterface
{
    /**
     * @var Order
     */
    protected $order;

    /**
     * @var OrderSlip[]
     */
    protected $orderSlips = [];

    protected function isProblematicOrderSlip(OrderSlip $orderSlip): bool
    {
        /** @var array<mixed> $orderSlipDetails */
        $orderSlipDetails = OrderSlip::getOrdersSlipDetail($orderSlip->id);

        // Vérification de la somme des produits HT
        $product_total_tax_excl = array_reduce(
            $orderSlipDetails,
            function ($sum, array $orderSlipDetail) {
                return $sum + $orderSlipDetail['total_price_tax_excl'];
            },
            0
        );

        if (floatval($orderSlip->total_products_tax_excl) != $product_total_tax_excl) {
            return true;
        }

        // Vérification de la somme des produits TTC
        $product_total_tax_incl = array_reduce(
            $orderSlipDetails,
            function ($sum, array $orderSlipDetail) {
                return $sum + $orderSlipDetail['total_price_tax_incl'];
            },
            0
        );

        // Vérifie la cohérence entre prix unitaire et quantité pour chaque ligne de l'avoir
        foreach ($orderSlipDetails as $orderSlipDetail) {
            if (
                round(floatval($orderSlipDetail['total_price_tax_excl']), 2) != round(floatval($orderSlipDetail['unit_price_tax_excl']) * intval($orderSlipDetail['product_quantity']), 2)
                || round(floatval($orderSlipDetail['total_price_tax_incl']), 2) != round(floatval($orderSlipDetail['unit_price_tax_incl']) * intval($orderSlipDetail['product_quantity']), 2)
            ) {
                return true;
            }
        }

        if (floatval($orderSlip->total_products_tax_incl) != $product_total_tax_incl) {
            return true;
        }

        if (floatval($orderSlip->amount) != floatval($orderSlip->total_products_tax_incl) + floatval($orderSlip->total_shipping_tax_incl)) {
            return true;
        }

        return false;
    }

    protected function isRepairableOrderSlip(OrderSlip $orderSlip): bool
    {
        return $this->isProblematicOrderSlip($orderSlip);
    }

    protected function repairOrderSlip(OrderSlip $orderSlip): bool
    {
        if (!$this->isRepairableOrderSlip($orderSlip)) {
            return false;
        }

        /** @var array<mixed> $orderSlipDetails */
        $orderSlipDetails = OrderSlip::getOrdersSlipDetail($orderSlip->id);

        // Vérification de la somme des produits HT
        $product_total_tax_excl = array_reduce(
            $orderSlipDetails,
            function ($sum, array $orderSlipDetail) {
                return $sum + $orderSlipDetail['total_price_tax_excl'];
            },
            0
        );

        $orderSlip->total_products_tax_excl = $product_total_tax_excl;

        // Vérification de la somme des produits TTC
        $product_total_tax_incl = array_reduce(
            $orderSlipDetails,
            function ($sum, array $orderSlipDetail) {
                return $sum + $orderSlipDetail['total_price_tax_incl'];
            },
            0
        );

        $orderSlip->total_products_tax_incl = $product_total_tax_incl;

        // Montant total de l'avoir
        $orderSlip->amount = floatval($orderSlip->total_products_tax_incl) + floatval($orderSlip->total_shipping_tax_incl);

        $orderSlip->save();

        // Corrige la cohérence entre prix unitaire et quantité pour chaque ligne de l'avoir
        foreach ($orderSlipDetails as $orderSlipDetail) {
            $detail_unit_price_tax_excl = round(floatval($orderSlipDetail['total_price_tax_excl']) / intval($orderSlipDetail['product_quantity']), 3);
            $detail_unit_price_tax_incl = round(floatval($orderSlipDetail['total_price_tax_incl']) / intval($orderSlipDetail['product_quantity']), 3);

            if (
                $detail_unit_price_tax_excl != floatval($orderSlipDetail['unit_price_tax_excl'])
                || $detail_unit_price_tax_incl != floatval($orderSlipDetail['unit_price_tax_incl'])
            ) {
                // Mise à jour du OrderSlipDetail
                Db::getInstance(true)
                    ->update(
                        'order_slip_detail',
                        [
                            'unit_price_tax_excl' => $detail_unit_price_tax_excl,
                            'unit_price_tax_incl' => $detail_unit_price_tax_incl,
                        ],
                        ' id_order_slip = ' . (int) $orderSlipDetail['id_order_slip'] . ' AND id_order_detail = ' . (int) $orderSlipDetail['id_order_detail']
                    );
            }
        }

        return true;
    }

    public function __construct(Order $order)
    {
        $this->order = $order;
        $this->orderSlips = $order->getOrderSlipsCollection();
    }

    public function getErrorMessage(): string
    {
        return "Les valeurs d'un avoir ne sont pas cohérentes";
    }

    public function isProblematic(): bool
    {
        foreach ($this->orderSlips as $orderSlip) {
            if ($this->isProblematicOrderSlip($orderSlip)) {
                return true;
            }
        }

        return false;
    }

    public function isRepairable(): bool
    {
        foreach ($this->orderSlips as $orderSlip) {
            if ($this->isRepairableOrderSlip($orderSlip)) {
                return true;
            }
        }

        return false;
    }

    public function repair(): bool
    {
        $ret = false;

        foreach ($this->orderSlips as $orderSlip) {
            if ($this->repairOrderSlip($orderSlip)) {
                $ret = true;
            }
        }

        return $ret;
    }
}
