<?php

namespace domain\Order\Order;

use common\components\Tiller\TillerClientInterface;
use common\components\Tiller\TillerClientV2;
use common\components\Tiller\TillerClientV3;
use common\helpers\MeanPayment;
use domain\Order\OrderStatus\OrderStatus;
use domain\Order\ProductOrder\ProductOrderSolver;
use domain\Producer\Producer\ProducerSolver;
use domain\_\AbstractManager;

class TillerManager extends AbstractManager
{
    protected ?bool $tillerActivated;
    protected ProducerSolver $producerSolver;
    protected TillerClientInterface $tillerClient;
    protected OrderSolver $orderSolver;
    protected OrderBuilder $orderBuilder;
    protected ProductOrderSolver $productOrderSolver;

    public function loadDependencies(): void
    {
        $this->producerSolver = $this->loadService(ProducerSolver::class);
        if($this->producerSolver->getProducerContext(false)) {
            $this->tillerActivated = $this->producerSolver->getConfig('tiller');
            $this->tillerClient = $this->getClient();
        }
        $this->orderSolver = $this->loadService(OrderSolver::class);
        $this->orderBuilder = $this->loadService(OrderBuilder::class);
        $this->productOrderSolver = $this->loadService(ProductOrderSolver::class);
    }

    public function getClient(): ?TillerClientInterface
    {
        $apiVersion = $this->producerSolver->getConfig('tiller_api_version');
        if($apiVersion == 'v2') {
            return new TillerClientV2(
                $this->producerSolver->getConfig('tiller_provider_token'),
                $this->producerSolver->getConfig('tiller_restaurant_token')
            );
        }
        elseif($apiVersion == 'v3') {
            return new TillerClientV3(
                $this->producerSolver->getConfig('tiller_store_id'),
                $this->producerSolver->getConfig('tiller_access_token')
            );
        }

        return null;
    }

    public function getUrlAuthorizeCode(): string
    {
        return $this->tillerClient->getUrlAuthorizeCode(
            $this->producerSolver->getConfig('tiller_client_id'),
            $this->producerSolver->getConfig('tiller_redirect_uri')
        );
    }

    public function isAuthenticated(): bool
    {
        return $this->tillerClient->isAuthenticated();
    }

    public function synchronizeDistribution(string $date): array
    {
        $return = [];

        if($this->tillerActivated) {
            $isSynchro = $this->isSynchronized($date);

            if (!$isSynchro) {
                $orders = Order::searchAll([
                    'distribution.date' => $date,
                    'order.tiller_synchronization' => 1,
                ], [
                    'conditions' => OrderRepositoryQuery::getSqlFilterIsValid()
                ]);

                if ($orders && count($orders)) {
                    foreach ($orders as $order) {
                        $res = $this->synchronizeOrder($order);
                        if($res) {
                            $return[] = $res;
                        }
                    }
                }
            }
        }

        return $return;
    }

    public function synchronizeOrder(Order $order, bool $force = false)
    {
        $apiVersion = $this->producerSolver->getConfig('tiller_api_version');
        $date = $order->distribution->date;
        $strDate = date('Y-m-d\T12:i:s+0000', strtotime($date) + 1);
        $datetime = new \DateTime(date('Y-m-d 12:i:s', strtotime($date)));
        $this->orderBuilder->initOrder($order);
        $lines = [];

        foreach ($order->productOrder as $productOrder) {
            // v3
            if($apiVersion == 'v3') {
                $amount = round($this->productOrderSolver->getPriceWithTax($productOrder) * 100);

                // classique
                if(is_int($productOrder->quantity)) {
                    $quantity = $productOrder->quantity;
                }
                // vrac
                else {
                    $amount = $amount * $productOrder->quantity;
                    $quantity = 1;
                }

                $lines[] = [
                    'name' => $productOrder->product->name,
                    'unitPrice' => [
                        'amount' => $amount,
                    ],
                    'taxRate' => $productOrder->taxRate->value * 100,
                    'quantity' => $quantity
                ];
            }
            // v2
            else {
                $lines[] = [
                    'name' => $productOrder->product->name,
                    'price' => $this->productOrderSolver->getPriceWithTax($productOrder) * 100 * $productOrder->quantity,
                    'tax' => $productOrder->taxRate->value * 100,
                    'date' => $strDate,
                    'quantity' => $productOrder->quantity
                ];
            }
        }

        $typePaymentTiller = '';
        if ($order->mean_payment == MeanPayment::MONEY) {
            $typePaymentTiller = 'CASH';
        }
        if ($order->mean_payment == MeanPayment::CREDIT_CARD
            || $order->mean_payment == MeanPayment::CREDIT
            || $order->mean_payment == MeanPayment::TRANSFER
            || $order->mean_payment == MeanPayment::OTHER) {
            $typePaymentTiller = 'CARD';
        }
        if ($order->mean_payment == MeanPayment::CHEQUE) {
            $typePaymentTiller = 'BANK_CHECK';
        }
        if (!strlen($typePaymentTiller) || !$order->mean_payment) {
            $typePaymentTiller = 'CASH';
        }

        if (!$this->isSynchronized($date, $order->id) || $force) {
            // v3
            if($apiVersion == 'v3') {
                $payments = [];
                $amountPayment = round($this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_PAID) * 100);
                if($amountPayment) {
                    $payments[] = [
                        'externalId' => ''.$order->id,
                        'amount' => $amountPayment
                    ];
                }

                $returnTiller = $this->tillerClient->postOrder([
                    'externalId' => ''.$order->id,
                    'purchaseRequestType' => 'clickAndCollect',
                    'date' => $datetime->format(\DateTime::ATOM),
                    'order' => [
                        'currencyCode' => 'EUR',
                        'itemLines' => $lines,
                        'payments' => $payments
                    ]
                ]);
            }
            // v2
            else {
                $returnTiller = $this->tillerClient->postOrder([
                    'externalId' => $order->id,
                    'type' => 1,
                    'status' => 'IN_PROGRESS',
                    'openDate' => $strDate,
                    'closeDate' => $strDate,
                    'lines' => $lines,
                    'payments' => [
                        [
                            'type' => $typePaymentTiller,
                            'amount' => $this->orderSolver->getOrderAmountWithTax(
                                    $order,
                                    Order::AMOUNT_PAID
                                ) * 100,
                            'status' => 'ACCEPTED',
                            'date' => $strDate
                        ]
                    ]
                ]);
            }

            $returnTillerObject = json_decode($returnTiller);
            if($apiVersion == 'v3') {
                $order->tiller_external_id = '' . $returnTillerObject->referenceId;
            }
            else {
                $order->tiller_external_id = '' . $returnTillerObject->id;
            }
            $order->save();

            return $returnTiller;
        }

        return null;
    }

    public function isSynchronized($date, $idOrder = null): bool
    {
        if ($this->tillerActivated) {
            $ordersTiller = $this->tillerClient->getOrders($date);

            $ordersOpendistrib = Order::searchAll([
                'distribution.date' => $date,
                'order.tiller_synchronization' => 1,
            ], [
                'conditions' => OrderRepositoryQuery::getSqlFilterIsValid()
            ]);

            $ordersOpendistribSynchro = [];

            if ($ordersOpendistrib) {
                foreach ($ordersOpendistrib as $orderOpendistrib) {
                    $this->orderBuilder->initOrder($orderOpendistrib);

                    if($orderOpendistrib->tiller_external_id) {
                        $ordersOpendistribSynchro[$orderOpendistrib->id] = true;
                    }
                    else {
                        $ordersOpendistribSynchro[$orderOpendistrib->id] = false;
                    }

                    /*if (isset($ordersTiller->orders)) {
                        foreach ($ordersTiller->orders as $orderTiller) {
                            if ($orderOpendistrib->tiller_external_id == $orderTiller->id) {
                                $amountTotalPaidOrderOpendistrib = (int)round(
                                    $this->orderSolver->getOrderAmountWithTax($orderOpendistrib, Order::AMOUNT_PAID) * 100
                                );
                                if ($amountTotalPaidOrderOpendistrib >= (int)$orderTiller->currentPayedAmount
                                    || $amountTotalPaidOrderOpendistrib >= (int)$orderTiller->currentBill) {
                                    $ordersOpendistribSynchro[$orderOpendistrib->id] = true;
                                }
                            }
                        }
                    }*/
                }
            }

            if($idOrder && isset($ordersOpendistribSynchro[$idOrder])) {
                return $ordersOpendistribSynchro[$idOrder];
            }
            else {
                foreach ($ordersOpendistribSynchro as $idOrder => $isSynchro) {
                    if (!$isSynchro) {
                        return false;
                    }
                }
            }

            return true;
        }

        return false;
    }
}