<?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\Sellerinfo;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoCommission;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoCommissionBase;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoCommissionRate;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoOrder;
use PrestaShop\Module\AgileMultisellerPro\Form\Configuration\Commissions\DataConfiguration as CommissionsDataConfiguration;
use PrestaShop\Module\AgileMultisellerPro\Form\Configuration\DataConfiguration;

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

class SellerinfoCommissionRepository extends EntityRepository
{
    public const VOUCHER_COST_AT_STORE = 1;
    public const VOUCHER_COST_AT_SELLER = 2;

    public const COMISSION_MODE_SELLER = 0;
    public const COMISSION_MODE_CATEGORY = 1;

    public const SELLER_PAID_TO_STORE = 101;
    public const STORE_PAID_TO_SELLER = 102;
    public const RECORD_TYPE_BUYER_PAY_STORE = 3;
    public const RECORD_TYPE_BUYER_PAY_BOTH = 2;
    public const RECORD_TYPE_BUYER_PAY_SELLER = 1;
    public const RECORD_TYPE_ORDER_CANCELLATION = -1;

    public function updateBalance($id_sellerinfo, $id_commission)
    {
        $sql = 'SELECT SUM(record_balance) as balance
            FROM `' . _DB_PREFIX_ . 'sellerinfo_commission`
            WHERE id_sellerinfo = ' . (int) $id_sellerinfo . '
            AND id_commission <= ' . (int) $id_commission;

        $balance = (float) \Db::getInstance()->getValue($sql);

        $sql = 'UPDATE`' . _DB_PREFIX_ . 'sellerinfo_commission`
            SET balance=' . (float) $balance . ' WHERE id_sellerinfo = ' . (int) $id_sellerinfo .
            ' AND id_commission=' . (int) $id_commission;

        \Db::getInstance()->Execute($sql);
    }

    public function createSellerCommission($order, $order_origin = 0)
    {
        $include_shipping = (int) \Configuration::get(CommissionsDataConfiguration::ASC_SHIPPING_INCLUDE) == 1;
        $include_tax = (int) \Configuration::get(CommissionsDataConfiguration::ASC_TAX_INCLUDE) == 1;
        $after_discount = (int) \Configuration::get(CommissionsDataConfiguration::ASC_VOUCHER_COST) == self::VOUCHER_COST_AT_SELLER;

        $sellerInfoOrderRepository = $this->getEntityManager()->getRepository(SellerinfoOrder::class);

        $seller_sales_4com = $sellerInfoOrderRepository->getSellerSalesFromOrder(
            $order->id,
            $include_shipping,
            $after_discount,
            $include_tax
        );

        $seller_sales_original = $sellerInfoOrderRepository->getSellerSalesFromOrder(
            $order->id,
            true,
            $after_discount,
            true
        );

        $currency_commission = new \Currency((int) \Configuration::get(CommissionsDataConfiguration::ASC_COMMISSION_CURRENCY));
        $currency_order = new \Currency($order->id_currency);

        $sellerinfoCommissionRateRepository = $this->getEntityManager()->getRepository(SellerinfoCommissionRate::class);
        $sellerinfoCommissionBaseRepository = $this->getEntityManager()->getRepository(SellerinfoCommissionBase::class);

        foreach ($seller_sales_4com as $idSellerinfo => $seller_sales) {
            $sellerInfo = $this->getEntityManager()->getRepository(Sellerinfo::class)
                ->findOneBy(['idSellerinfo' => (int) $idSellerinfo]);

            if (!$sellerInfo) {
                continue;
            }

            $sellerCommission = $this->getCommissionRecordID($order->id, $sellerInfo);

            if ($sellerCommission) {
                continue;
            }

            $seller_final_sales = $seller_sales *
                $currency_commission->conversion_rate / $currency_order->conversion_rate;

            $seller_final_sales_original =
                $seller_sales_original[$idSellerinfo] *
                $currency_commission->conversion_rate / $currency_order->conversion_rate;

            $range_commission = 0;
            $base_commission = 0;

            $commission_rate =
                $sellerinfoCommissionRateRepository->getRate(
                    $sellerInfo,
                    $seller_final_sales,
                    SellerinfoCommissionRateRepository::RATE_FOR_COMMISSION
                );

            $deduction_rate =
                $sellerinfoCommissionRateRepository->getRate(
                    $sellerInfo,
                    $seller_final_sales,
                    SellerinfoCommissionRateRepository::RATE_FOR_DEDUCTION
                );

            $range_commission =
                $seller_sales_4com[$idSellerinfo] *
                (1 - $deduction_rate * 0.01) *
                (float) $commission_rate * 0.01 *
                $currency_commission->conversion_rate / $currency_order->conversion_rate;

            $base_commission = $sellerinfoCommissionBaseRepository->getBaseCommissionRate($sellerInfo);

            $deduction_amount =
                $seller_sales_4com[$idSellerinfo] * $deduction_rate * 0.01 *
                    $currency_commission->conversion_rate / $currency_order->conversion_rate;

            $sellerSales =
                $seller_final_sales_original -
                $base_commission - $range_commission -
                $deduction_amount;

            $sellerCommission = new SellerinfoCommission();

            $sellerCommission->setSellerinfo($sellerInfo)
                ->setIdOrder((int) $order->id)
                ->setIdCurrency((int) $currency_commission->id)
                ->setSalesAmount($seller_final_sales_original)
                ->setBaseCommission($base_commission)
                ->setRangeCommission($range_commission)
                ->setDeductionAmount($deduction_amount)
                ->setSellerSales($sellerSales)
                ->setRecordType(self::RECORD_TYPE_BUYER_PAY_STORE)
                ->setRecordBalance($sellerSales)
                ->setPaymentTxnId('')
                ->setMemo(\Mail::l('Order Confirmed'));

            $this->getEntityManager()->persist($sellerCommission);
            $this->getEntityManager()->flush();

            $this->updateRecordType(
                $sellerInfo,
                $order->id,
                (int) \Configuration::get(DataConfiguration::AGILE_MS_PAYMENT_MODE),
                ''
            );
        }
    }

    public function cancelSellerCommission($order)
    {
        $sellerinfoOrder = $this->getEntityManager()->getRepository(SellerinfoOrder::class);

        foreach ($sellerinfoOrder->findBy(['idOrder' => $order->id]) as $sellerOrder) {
            $sellerInfo = $sellerOrder->getSellerinfo();

            $sellerCommissionCancel = $this->findOneBy([
                'sellerInfo' => $sellerInfo,
                'idOrder' => $order->id,
                'recordType' => self::RECORD_TYPE_ORDER_CANCELLATION,
            ]);

            if ($sellerCommissionCancel && $sellerCommissionCancel->getIdCommission()) {
                continue;
            }

            $sellerCommission = $this->getCommissionRecordID($order->id, $sellerInfo);

            if ($sellerCommission && $sellerCommission->getIdCommission()) {
                $sellerCommissionCancel = new SellerinfoCommission();

                $sellerCommissionCancel
                    ->setSellerinfo($sellerCommission->getSellerinfo())
                    ->setIdOrder($sellerCommission->getIdOrder())
                    ->setIdCurrency($sellerCommission->getIdCurrency())
                    ->setSalesAmount(0 - $sellerCommission->getSalesAmount())
                    ->setBaseCommission(0 - $sellerCommission->getBaseCommission())
                    ->setRangeCommission(0 - $sellerCommission->getRangeCommission())
                    ->setSellerSales(0 - $sellerCommission->getSellerSales())
                    ->setRecordBalance(0 - $sellerCommission->getRecordBalance())
                    ->setRecordType(self::RECORD_TYPE_ORDER_CANCELLATION)
                    ->setBalance($sellerCommission->getBalance())
                    ->setMemo(\Mail::l('Order cancalled'))
                    ->setDeductionAmount(0 - $sellerCommission->getDeductionAmount())
                ;

                $this->getEntityManager()->persist($sellerCommissionCancel);
                $this->getEntityManager()->flush();

                $this->updateBalance(
                    $sellerCommissionCancel->getSellerinfo()->getIdSellerinfo(),
                    $sellerCommissionCancel->getIdCommission()
                );
            }
        }
    }

    protected function getCommissionRecordID($idOrder, $sellerInfo)
    {
        return $this->findOneBy([
            'sellerInfo' => $sellerInfo,
            'idOrder' => $idOrder,
            'recordType' => [self::RECORD_TYPE_BUYER_PAY_STORE, self::RECORD_TYPE_BUYER_PAY_SELLER, self::RECORD_TYPE_BUYER_PAY_BOTH],
        ]);
    }

    public function updateRecordType($sellerInfo, $idOrder, $recordType, $txnId)
    {
        $conn = $this->getEntityManager()->getConnection();

        if ($sellerInfo->isPaymentCollection() == 1) {
            $recordType = 3;
        }

        $order = new \Order($idOrder);

        if ($recordType == self::RECORD_TYPE_BUYER_PAY_BOTH) {
            $record_balance = ' 0 ';

            if ($order->module == 'agilepaypalparallel') {
                $record_balance = ' 0 + seller_sales ';
            }
        } elseif ($recordType == self::RECORD_TYPE_BUYER_PAY_SELLER) {
            $record_balance = ' base_commission - range_commission ';

            if ($order->module == 'agilepaypalparallel') {
                $record_balance = ' seller_sales - base_commission - range_commission ';
            }
        } else {
            $record_balance = 'seller_sales';
        }

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_commission` SET
            `record_type` =:recordType,
            `payment_txn_id` =:txnId,
            `record_balance` = (' . $record_balance . ')
            WHERE id_order =:idOrder
        ';

        $conn->executeQuery($sql, ['recordType' => $recordType, 'txnId' => $txnId, 'idOrder' => $idOrder]);

        foreach ($this->findBy(['idOrder' => (int) $idOrder]) as $record) {
            $this->updateBalance(
                $record->getSellerinfo()->getIdSellerinfo(),
                $record->getIdCommission()
            );
        }
    }
}
