<?php
/**
 * 2007-2023 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to http://www.prestashop.com for more information.
 *
 *  @author    PrestaShop SA <contact@prestashop.com>
 *  @copyright 2007-2023 PrestaShop SA
 *  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 *  International Registered Trademark & Property of PrestaShop SA
 */
declare(strict_types=1);

namespace PrestaShop\Module\AgileMultisellerPro\Repository;

use Doctrine\ORM\EntityRepository;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoCartCarrier;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoDelivery;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoProduct;
use PrestaShop\Module\AgileMultisellerPro\Helper\AgileHelper;

if (!defined('_PS_VERSION_')) {
    exit;
}

class SellerInfoShippingRepository extends EntityRepository
{
    public function getSellerCarrierStatus(int $idSellerInfo, int $idCarrierReference): bool
    {
        /** @var QueryBuilder $qb */
        $qb = $this->createQueryBuilder('sis')
            ->select('sis.active') // Select only the 'active' field
            ->where('sis.idSellerInfo = :idSellerInfo')
            ->andWhere('sis.idCarrierReference = :idCarrierReference')
            ->setParameter('idSellerInfo', $idSellerInfo)
            ->setParameter('idCarrierReference', $idCarrierReference)
        ;

        // Use getOneOrNullResult() to get a single result or null
        $result = $qb->getQuery()->getOneOrNullResult();

        // Extract the 'active' value from the result or set it to null
        $activeValue = false;
        if ($result !== null) {
            $activeValue = $result['active'];
        }

        return (bool) $activeValue;
    }

    public function getFreeShippingStatus(int $idSellerInfo, int $idCarrierReference)
    {
        /** @var QueryBuilder $qb */
        $qb = $this->createQueryBuilder('sis')
            ->select('sis.isFree AS isFree')
            ->where('sis.idSellerInfo = :idSellerInfo')
            ->andWhere('sis.idCarrierReference = :idCarrierReference')
            ->setParameter('idSellerInfo', $idSellerInfo)
            ->setParameter('idCarrierReference', $idCarrierReference)
        ;

        // Use getOneOrNullResult() to get a single result or null
        $result = $qb->getQuery()->getOneOrNullResult();

        // Extract the 'active' value from the result or set it to null
        $status = null;
        if ($result !== null) {
            $status = $result['isFree'];
        }

        return $status;
    }

    public function groupProductsBySellerAndCalculateShipping($products, $idZone, $idCart)
    {
        if (!$products) {
            return null;
        }
        $em = AgileHelper::buildContainer()->get('doctrine.orm.entity_manager');

        $sellerinfoProductRepository = $em->getRepository(SellerinfoProduct::class);
        $sellerinfoDeliveryRepository = $em->getRepository(SellerinfoDelivery::class);

        $defaultCurrency = \Currency::getDefaultCurrency();
        $context = \Context::getContext();

        $shippingData = [];

        foreach ($products as $product) {
            $sellerProduct = $sellerinfoProductRepository->findOneBy([
                'idProduct' => $product['id_product'],
            ]);

            $idSellerinfo = ($sellerProduct) ? $sellerProduct->getSellerinfo()->getIdSellerinfo() : 0;

            if (!isset($shippingData[$idSellerinfo]['totalPriceSumDefCurrency'])) {
                $shippingData[$idSellerinfo]['totalPriceSumDefCurrency'] = 0;
            }

            if (!isset($shippingData[$idSellerinfo]['weightSum'])) {
                $shippingData[$idSellerinfo]['weightSum'] = 0;
            }

            $shippingData[$idSellerinfo]['idSellerinfo'] = $idSellerinfo;

            $shippingData[$idSellerinfo]['totalPriceSumDefCurrency'] += \Tools::convertPriceFull(
                $product['total'],
                $context->currency,
                $defaultCurrency
            );

            $shippingData[$idSellerinfo]['weightSum'] += $product['weight'] * $product['quantity'];

            $shippingData[$idSellerinfo]['products'][] = $product;
            $shippingData[$idSellerinfo]['carriers'] = [];
        }

        $taxConfigurations = new \TaxConfiguration();

        foreach ($shippingData as $key => $shipping) {
            if ($key == 0) {
                $adminCarriers = \Carrier::getCarriers(
                    $context->language->id,
                    true,
                    false,
                    $idZone
                );

                foreach ($adminCarriers as $adminCarrier) {
                    $carrierObj = new \Carrier($adminCarrier['id_carrier']);

                    $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['adminCarrier'] = $carrierObj;
                    $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['sellerCarrier'] = null;

                    if ($adminCarrier['shipping_method'] == 2) {
                        if (\Carrier::checkDeliveryPriceByPrice(
                            $adminCarrier['id_carrier'],
                            $shipping['totalPriceSumDefCurrency'],
                            $idZone
                        )) {
                            $carrierShippingPrice = $carrierObj->getDeliveryPriceByPrice(
                                $shipping['totalPriceSumDefCurrency'],
                                $idZone
                            );
                        } else {
                            $carrierShippingPrice = false;
                        }
                    } else {
                        if (\Carrier::checkDeliveryPriceByWeight(
                            $adminCarrier['id_carrier'],
                            $shipping['weightSum'],
                            $idZone
                        )) {
                            $carrierShippingPrice = $carrierObj->getDeliveryPriceByWeight(
                                $shipping['weightSum'],
                                $idZone
                            );
                        } else {
                            $carrierShippingPrice = false;
                        }
                    }

                    if ($carrierShippingPrice !== false) {
                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['carrierShippingPrice'] =
                            $carrierShippingPrice;

                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['carrierShippingPriceWithTax'] =
                            $carrierShippingPrice * (1 + (AgileHelper::getCarrierTax(
                                $carrierObj,
                                $idCart,
                                true
                            ) / 100));

                        $currentCurrencyPrice = \Tools::convertPriceFull(
                            $carrierShippingPrice,
                            $defaultCurrency,
                            $context->currency
                        );
                        $currentCurrencyPriceWithTax = \Tools::convertPriceFull(
                            $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['carrierShippingPriceWithTax'],
                            $defaultCurrency,
                            $context->currency
                        );

                        $smarty = [];
                        $currentCurrencyPriceFormatted = \Tools::displayPriceSmarty(
                            [
                                'price' => $taxConfigurations->includeTaxes()
                                    ? $currentCurrencyPriceWithTax
                                    : $currentCurrencyPrice,
                            ],
                            $smarty
                        );

                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['currentCurrencyPrice'] =
                            $currentCurrencyPrice;
                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['currentCurrencyPriceFormatted'] =
                            $currentCurrencyPriceFormatted;

                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['available'] = true;
                    } else {
                        $shippingData[$key]['carriers'][$adminCarrier['id_reference']]['available'] = false;
                    }
                }
            } else {
                $sellerCarriers = $this->findBy([
                    'idSellerInfo' => $key,
                    'active' => true,
                ]);

                foreach ($sellerCarriers as $n => $sellerCarrier) {
                    $idCarrierReference = $sellerCarrier->getIdCarrierReference();
                    $adminCarrier = \Carrier::getCarrierByReference($idCarrierReference);

                    if (isset($adminCarrier->active) && $adminCarrier->active == true) {
                        $shippingData[$key]['carriers'][$idCarrierReference]['adminCarrier'] = $adminCarrier;
                        $shippingData[$key]['carriers'][$idCarrierReference]['sellerCarrier'] = $sellerCarrier;
                    } else {
                        continue;
                    }

                    $sellerCarrierDeliveries = $sellerinfoDeliveryRepository->findBy([
                        'idSellerinfo' => $sellerCarrier->getIdSellerinfo(),
                        'idCarrierReference' => $idCarrierReference,
                    ]);

                    if (!empty($sellerCarrierDeliveries)) {
                        $checkZoneExist = false;
                        foreach ($sellerCarrierDeliveries as $delivery) {
                            if ($delivery->getIdRangeZone() == $idZone) {
                                $checkZoneExist = true;
                                break;
                            }
                        }

                        if ($checkZoneExist) {
                            if ($sellerCarrier->getIsFree() == true) {
                                $carrierShippingPrice = 0;
                                $shippingData[$key]['carriers'][$idCarrierReference]['available'] = true;
                            } else {
                                $searchValue = $sellerCarrier->getIdShippingMethod() == 2
                                    ? $shipping['totalPriceSumDefCurrency']
                                    : $shipping['weightSum'];

                                $carrierShippingPrice = $sellerinfoDeliveryRepository->getDeliveryPriceByRange(
                                    $searchValue,
                                    $sellerCarrier->getIdSellerinfo(),
                                    $idCarrierReference,
                                    $sellerCarrier->getIdShippingMethod(),
                                    $idZone
                                );

                                if ($carrierShippingPrice === false) {
                                    $carrierShippingPrice = $sellerinfoDeliveryRepository->getDeliveryMaxPrice(
                                        $sellerCarrier->getIdSellerinfo(),
                                        $idCarrierReference,
                                        $sellerCarrier->getIdShippingMethod(),
                                        $idZone
                                    );
                                }

                                if ($carrierShippingPrice === null) {
                                    $carrierShippingPrice = false;
                                }
                            }

                            if ($carrierShippingPrice !== false) {
                                $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPrice'] =
                                    $carrierShippingPrice;

                                $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPriceWithTax'] =
                                    $carrierShippingPrice * (1 + (AgileHelper::getCarrierTax(
                                        $adminCarrier,
                                        $idCart,
                                        true
                                    ) / 100));

                                $currentCurrencyPrice = \Tools::convertPriceFull(
                                    $carrierShippingPrice,
                                    $defaultCurrency,
                                    $context->currency
                                );
                                $currentCurrencyPriceWithTax = \Tools::convertPriceFull(
                                    $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPriceWithTax'],
                                    $defaultCurrency,
                                    $context->currency
                                );

                                $smarty = [];
                                $currentCurrencyPriceFormatted = \Tools::displayPriceSmarty(
                                    [
                                        'price' => $taxConfigurations->includeTaxes()
                                            ? $currentCurrencyPriceWithTax
                                            : $currentCurrencyPrice,
                                    ],
                                    $smarty
                                );

                                $shippingData[$key]['carriers'][$idCarrierReference]['currentCurrencyPrice'] =
                                    $currentCurrencyPrice;
                                $shippingData[$key]['carriers'][$idCarrierReference]['currentCurrencyPriceFormatted'] =
                                    $currentCurrencyPriceFormatted;

                                $shippingData[$key]['carriers'][$idCarrierReference]['available'] = true;
                            } else {
                                $shippingData[$key]['carriers'][$idCarrierReference]['available'] = false;
                            }
                        } else {
                            $shippingData[$key]['carriers'][$idCarrierReference]['available'] = false;
                        }
                    } else {
                        if ($sellerCarrier->getIdShippingMethod() == 2) {
                            if (\Carrier::checkDeliveryPriceByPrice(
                                $adminCarrier->id,
                                $shipping['totalPriceSumDefCurrency'],
                                $idZone
                            )) {
                                $carrierShippingPrice = $adminCarrier->getDeliveryPriceByPrice(
                                    $shipping['totalPriceSumDefCurrency'],
                                    $idZone
                                );
                            } else {
                                $carrierShippingPrice = false;
                            }
                        } else {
                            if (\Carrier::checkDeliveryPriceByWeight(
                                $adminCarrier->id,
                                $shipping['weightSum'],
                                $idZone
                            )) {
                                $carrierShippingPrice = $adminCarrier->getDeliveryPriceByWeight(
                                    $shipping['weightSum'],
                                    $idZone
                                );
                            } else {
                                $carrierShippingPrice = false;
                            }
                        }

                        if ($carrierShippingPrice !== false) {
                            $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPrice'] =
                                $carrierShippingPrice;

                            $rate = (float) AgileHelper::getCarrierTax(
                                $adminCarrier,
                                $idCart,
                                true
                            );
                            $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPriceWithTax'] = $carrierShippingPrice * (1 + $rate / 100);

                            $smarty = [];

                            $currentCurrencyPrice = \Tools::convertPriceFull(
                                $carrierShippingPrice,
                                $defaultCurrency,
                                $context->currency
                            );
                            $currentCurrencyPriceWithTax = \Tools::convertPriceFull(
                                $shippingData[$key]['carriers'][$idCarrierReference]['carrierShippingPriceWithTax'],
                                $defaultCurrency,
                                $context->currency
                            );

                            $currentCurrencyPriceFormatted = \Tools::displayPriceSmarty(
                                [
                                    'price' => $taxConfigurations->includeTaxes()
                                        ? $currentCurrencyPriceWithTax
                                        : $currentCurrencyPrice,
                                ],
                                $smarty
                            );

                            $shippingData[$key]['carriers'][$idCarrierReference]['currentCurrencyPrice'] =
                                $currentCurrencyPrice;
                            $shippingData[$key]['carriers'][$idCarrierReference]['currentCurrencyPriceFormatted'] =
                                $currentCurrencyPriceFormatted;

                            $shippingData[$key]['carriers'][$idCarrierReference]['available'] = true;
                        } else {
                            $shippingData[$key]['carriers'][$idCarrierReference]['available'] = false;
                        }
                    }
                }
            }
        }

        return $shippingData;
    }

    public function getTotalShippingCost($products, $idCart, $idCustomer, $idAddressDelivery, $use_tax = true)
    {
        $idCart = (int) $idCart;

        $idZone = AgileHelper::getZoneID(
            $idAddressDelivery,
            $idCustomer
        );

        $shippingData = $this->groupProductsBySellerAndCalculateShipping(
            $products,
            $idZone,
            $idCart
        );

        $em = AgileHelper::buildContainer()->get('doctrine.orm.entity_manager');

        $sellerinfoCartCarrierRepository = $em->getRepository(SellerinfoCartCarrier::class);

        $_total_shipping['with_tax'] = 0;
        $_total_shipping['without_tax'] = 0;
        if (!$shippingData) {
            return ($use_tax) ? $_total_shipping['with_tax'] : $_total_shipping['without_tax'];
        }

        foreach ($shippingData as $idSellerinfo => $shipping) {
            $sellerCartCarrier = $sellerinfoCartCarrierRepository->findOneBy([
                'idSellerInfo' => $idSellerinfo,
                'idCart' => $idCart,
            ]);
            if ($sellerCartCarrier) {
                $idCartCarrierReference = $sellerCartCarrier->getIdCarrierReference();
                $currentWithoutTax = 0;
                if (isset($shipping['carriers'][$idCartCarrierReference])
                    && $shipping['carriers'][$idCartCarrierReference]['available'] == true
                ) {
                    $currentWithoutTax =
                        $shipping['carriers'][$idCartCarrierReference]['currentCurrencyPrice'];
                } else {
                    foreach ($shipping['carriers'] as $idCarrierReference => $carrier) {
                        if ($carrier['available'] == true) {
                            $idCartCarrierReference = $idCarrierReference;
                            $sellerCartCarrier->setIdCarrierReference($idCarrierReference);
                            $sellerCartCarrier->setWeight($shipping['weightSum']);
                            $sellerCartCarrier->setShippingCost($carrier['carrierShippingPriceWithTax']);
                            $em->persist($sellerCartCarrier);
                            $em->flush();
                            $currentWithoutTax = $carrier['currentCurrencyPrice'];
                            break;
                        }
                    }
                }
                $_total_shipping['without_tax'] += $currentWithoutTax;

                if (isset($shipping['carriers'][$idCartCarrierReference]['adminCarrier'])) {
                    $rate = (float) AgileHelper::getCarrierTax(
                        $shipping['carriers'][$idCartCarrierReference]['adminCarrier'],
                        $idCart,
                        $use_tax
                    );
                    $currentWithTax = $currentWithoutTax * (1 + $rate / 100);

                    $_total_shipping['with_tax'] += $currentWithTax;
                }
            } else {
                foreach ($shipping['carriers'] as $idCarrierReference => $carrier) {
                    if ($carrier['available'] == true) {
                        $sellerCartCarrier = new SellerinfoCartCarrier();
                        $sellerCartCarrier->setIdSellerInfo($idSellerinfo);
                        $sellerCartCarrier->setIdCarrierReference($idCarrierReference);
                        $sellerCartCarrier->setIdCart($idCart);
                        $sellerCartCarrier->setWeight($shipping['weightSum']);
                        $sellerCartCarrier->setShippingCost($carrier['carrierShippingPriceWithTax']);
                        $em->persist($sellerCartCarrier);
                        $em->flush();
                        $currentWithoutTax = $carrier['currentCurrencyPrice'];
                        $_total_shipping['without_tax'] += $currentWithoutTax;

                        $rate = (float) AgileHelper::getCarrierTax(
                            $carrier['adminCarrier'],
                            $idCart,
                            $use_tax
                        );

                        $currentWithTax = $currentWithoutTax * (1 + $rate / 100);

                        $_total_shipping['with_tax'] += $currentWithTax;
                        break;
                    }
                }
            }
        }

        return ($use_tax) ? $_total_shipping['with_tax'] : $_total_shipping['without_tax'];
    }
}
