<?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\SellerinfoMembershipCustomer;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoMembershipHistory;
use PrestaShop\Module\AgileMultisellerPro\Entity\SellerinfoMembershipType;
use PrestaShop\Module\AgileMultisellerPro\Helper\AgileHelperMembership;

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

class SellerInfoMembershipCustomerRepository extends EntityRepository
{
    public function getExpiryDate($id_customer, $id_lang)
    {
        if ((int) $id_customer <= 0) {
            return new \DateTime('2000-01-01 01:01:01');
        }

        $sql = ' SELECT mh.expiry_date
                FROM `' . _DB_PREFIX_ . 'sellerinfo_membership_customer` a
                    LEFT JOIN `' . _DB_PREFIX_ . 'customer` c ON a.id_customer = c.id_customer
                    LEFT JOIN `' . _DB_PREFIX_ . 'sellerinfo_membership_history` mh ON c.id_customer = mh.id_customer
                    LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (mh.id_order = od.id_order AND mh.id_product = od.product_id AND mh.id_product_attribute = od.product_attribute_id)
                    LEFT JOIN `' . _DB_PREFIX_ . 'order_state_lang` osl ON (mh.id_order_state=osl.id_order_state AND osl.id_lang=' . $id_lang . ')
                    LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (mh.id_product=pl.id_product AND pl.`id_lang` = ' . (int) $id_lang . ' AND pl.id_shop=' . (int) \Configuration::get('PS_SHOP_DEFAULT') . ')
                    LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON od.id_order = o.id_order
                    WHERE a.id_customer=' . (int) $id_customer . ' AND mh.id_order_state != 6 AND IFNULL(mh.is_cancelled,0) != 1
                    ORDER BY mh.id_order DESC;';

        $results = \Db::getInstance()->ExecuteS($sql);

        $membership = array_shift($results);

        if (!isset($membership)) {
            return new \DateTime('2000-01-01 01:01:01');
        }

        if (!isset($membership['expiry_date'])) {
            return new \DateTime('2000-01-01 01:01:01');
        }

        return new \DateTime($membership['expiry_date']);
    }

    public function getMembershipsForCsutomer($id_customer, $id_lang)
    {
        $sql = '
            SELECT mh.*, pl.name as membership, osl.name as status, IFNULL(mh.is_cancelled,0) AS is_cancelled,mh.date_cancelled,
                o.reference AS `order_reference`,
                smt.listing_max AS `max_products`
            FROM `' . _DB_PREFIX_ . 'sellerinfo_membership_customer` a
            LEFT JOIN `' . _DB_PREFIX_ . 'customer` c ON a.id_customer = c.id_customer
            LEFT JOIN `' . _DB_PREFIX_ . 'sellerinfo_membership_history` mh ON c.id_customer = mh.id_customer
            LEFT JOIN `' . _DB_PREFIX_ . 'order_detail` od ON (mh.id_order = od.id_order AND mh.id_product = od.product_id AND mh.id_product_attribute = od.product_attribute_id)
            LEFT JOIN `' . _DB_PREFIX_ . 'order_state_lang` osl ON (mh.id_order_state=osl.id_order_state AND osl.id_lang=' . (int) $id_lang . ')
            LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (mh.id_product=pl.id_product AND pl.`id_lang` = ' . (int) $id_lang . ' AND pl.id_shop=' . (int) \Configuration::get('PS_SHOP_DEFAULT') . ')
            LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON od.id_order = o.id_order
            LEFT JOIN ' . _DB_PREFIX_ . 'sellerinfo_membership_type AS smt ON (smt.id_product = mh.id_product)
            WHERE 1 AND IFNULL(mh.id_order,0) > 0
                AND a.id_customer=' . (int) $id_customer . '
            ORDER BY date_start DESC
        ';

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

    public function createMembershipData($id_order, $orderStatus)
    {
        if (!isset($orderStatus)) {
            return;
        }

        if ((int) $id_order == 0) {
            return;
        }

        if (
            $orderStatus->id != _PS_OS_PAYMENT_
            && $orderStatus->id != _PS_OS_WS_PAYMENT_
            && $orderStatus->id != (int) \Configuration::get('AGILE_MEMBERSHIP_FREE_TRIAL_STATE')
        ) {
            return;
        }

        $order = new \Order($id_order);
        if (!\Validate::isLoadedObject($order)) {
            return;
        }

        if (
            $this->_em->getRepository(SellerinfoMembershipHistory::class)->findOneBy([
                'idOrder' => $id_order,
                'idCustomer' => $order->id_customer,
            ])
        ) {
            return;
        }

        $context = \Context::getContext();

        $context->cart = new \Cart($order->id_cart);
        if (!\Validate::isLoadedObject($context->cart)) {
            return;
        }

        foreach ($context->cart->getProducts() as $key => $product) {
            if (
                $product['price'] == 0
                && $this->hasUsedBefore($product['id_product'], $order->id_customer)
                && \Configuration::get('AGILE_MEMBERSHIP_FREE_ONETIME_ONLY') == 1
            ) {
                continue;
            }

            if (!AgileHelperMembership::isProductInMembershipCategory($product['id_product'])) {
                continue;
            }

            $sellerinfoMembershipType = $this->_em->getRepository(SellerinfoMembershipType::class)
                ->findOneBy([
                    'idProduct' => $product['id_product'],
                ])
            ;

            if (!$sellerinfoMembershipType) {
                continue;
            }

            $sellerinfoMembershipCustomer = $this
                ->findOneBy([
                    'idCustomer' => $order->id_customer,
                ])
            ;

            if (!$sellerinfoMembershipCustomer) {
                $sellerinfoMembershipCustomer = new SellerinfoMembershipCustomer();
            }

            $sellerinfoMembershipCustomer
                ->setIdCustomer((int) $order->id_customer)
                ->setActivated(false)
                ->setDateAdd(new \DateTime())
                ->setSellerinfoMembershipType($sellerinfoMembershipType)
                ->setOrigin(1)
            ;

            $this->_em->persist($sellerinfoMembershipCustomer);
            $this->_em->flush();

            $mem_quantity = (int) $product['cart_quantity'];

            if ($product['price'] == 0) {
                $mem_quantity = 1;
            }

            $sellerinfoMembershipHistory = new SellerinfoMembershipHistory();

            $sellerinfoMembershipHistory
                ->setIdCustomer((int) $order->id_customer)
                ->setIdProduct((int) $product['id_product'])
                ->setIdProductAttribute((int) $product['id_product_attribute'])
                ->setQuantity($mem_quantity)
                ->setIdOrder((int) $order->id)
                ->setIdOrderState((int) $orderStatus->id)
                ->setInterval($sellerinfoMembershipType->getIntervalMembership())
                ->setUnits($sellerinfoMembershipType->getUnits())
                ->setIsCancelled(false)
            ;

            $date_start = $this->getExpiryDate($order->id_customer, $context->cart->id_lang);
            $today = new \DateTime(date('Y-m-d H:i:s'));
            $gracedays = (int) \Configuration::get('AGILE_MEMBERSHIP_PAUSE_GRACEDAYS');

            if ($date_start < $today && $gracedays <= 0) {
                $date_start = $today;
            }

            $sellerinfoMembershipHistory
                ->setDateAdd(new \DateTime())
                ->setDateStart($date_start)
                ->setExpiryDate($date_start)
            ;

            $this->_em->persist($sellerinfoMembershipHistory);
            $this->_em->flush();

            $units = $sellerinfoMembershipType->getUnits();
            if (is_null($units)) {
                $units = 0;
            }
            $interval = $sellerinfoMembershipType->getIntervalMembership();
            if (is_null($interval)) {
                $interval = 'DAY';
            }

            $sql = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_membership_history`
                SET expiry_date =  DATE_ADD(date_start, INTERVAL ' .
                    ($units * $mem_quantity) . ' ' . $interval .
                ')
                WHERE id_membership_history=' . (int) $sellerinfoMembershipHistory->getIdMembershipHistory();
            \Db::getInstance()->Execute($sql);

            $sql = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_membership_customer`
                SET activated = 1, activation_date = \'' . date('Y-m-d H:i:s') . '\'
                WHERE activated = 0 AND id_customer=' . (int) $order->id_customer;
            \Db::getInstance()->Execute($sql);
        }

        $this->updateEffectiveMembershipGroup($order->id_customer);
    }

    public function hasUsedBefore($id_product, $id_customer)
    {
        if ((int) $id_product <= 0) {
            return 0;
        }

        $sellerinfoMembershipHistory = $this->_em->getRepository(SellerinfoMembershipHistory::class)
            ->findOneBy([
                'idCustomer' => $id_customer,
                'idProduct' => $id_product,
            ]);

        if (!$sellerinfoMembershipHistory) {
            return 0;
        }

        return $sellerinfoMembershipHistory->getIdProduct();
    }

    public function updateEffectiveMembershipGroup($id_customer)
    {
        if ((int) $id_customer == 0) {
            return;
        }

        $customer = new \Customer($id_customer);

        if (!\Validate::isLoadedObject($customer)) {
            return;
        }

        $id_default_group = 0;

        $effectiveMembershipGroup = $this->getEffectiveMembershipGroup($id_customer);

        if (isset($effectiveMembershipGroup) && $effectiveMembershipGroup) {
            $id_membership_type = (int) $effectiveMembershipGroup['id_membership_type'];
            if ((int) $id_membership_type) {
                $sql0 = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_membership_customer`
                    SET id_membership_type=' . (int) $id_membership_type . '
                    WHERE id_customer =' . (int) $id_customer;

                \Db::getInstance()->execute($sql0);
            }

            $id_cur_group = (int) $effectiveMembershipGroup['id_group'];
            if (isset($id_cur_group) && (int) $id_cur_group > 0) {
                $id_default_group = (int) $id_cur_group;
            }
        }

        if ($id_default_group == 0) {
            $sql1 = 'DELETE FROM `' . _DB_PREFIX_ . 'customer_group`
                WHERE id_customer=' . (int) $id_customer . '
                    AND id_group IN (SELECT DISTINCT id_group FROM ' . _DB_PREFIX_ . 'sellerinfo_membership_type)';
            \Db::getInstance()->execute($sql1);

            $sql0 = 'SELECT id_group FROM ' . _DB_PREFIX_ . 'customer_group WHERE id_customer=' . (int) $id_customer;
            $rows = \Db::getInstance()->executeS($sql0);

            if (empty($rows)) {
                $id_default_group = 3;
            } else {
                foreach ($rows as $row) {
                    if ($row['id_group'] == $customer->id_default_group) {
                        $id_default_group = (int) $row['id_group'];
                    }
                }

                if ($id_default_group == 0) {
                    $id_default_group = (int) $rows[0]['id_group'];
                }
            }
        }

        if ($id_default_group == 0) {
            $id_default_group = 3;
        }

        $sql2 = 'REPLACE INTO `' . _DB_PREFIX_ . 'customer_group` (id_customer, id_group)
            VALUES (' . $id_customer . ',' . $id_default_group . ')';
        \Db::getInstance()->Execute($sql2);

        $sql2 = 'REPLACE INTO ' . _DB_PREFIX_ . 'customer_group
            (id_customer, id_group) VALUES (' . $id_customer . ',' . 3 . ')';
        \Db::getInstance()->Execute($sql2);

        $sql3 = 'UPDATE `' . _DB_PREFIX_ . 'customer`
            SET id_default_group = ' . $id_default_group . '
            WHERE id_customer=' . $id_customer;
        \Db::getInstance()->Execute($sql3);
    }

    public function getEffectiveMembershipGroup($id_customer)
    {
        if (!isset($id_customer) || (int) $id_customer <= 0) {
            return false;
        }

        $sql = '
            SELECT mh.id_customer,mt.id_group, mt.id_membership_type
            FROM `' . _DB_PREFIX_ . 'sellerinfo_membership_history` mh
            LEFT JOIN `' . _DB_PREFIX_ . 'sellerinfo_membership_type` mt ON mh.id_product=mt.id_product
            WHERE mh.id_customer =' . $id_customer . '
                AND mh.`expiry_date`>= \'' . date('Y-m-d H:i:s') . '\'
                AND IFNULL(mh.is_cancelled,0) = 0
            ORDER BY mh.expiry_date ASC
            ';

        $row = \Db::getInstance()->getRow($sql);

        return $row;
    }

    public function cancelMembership($id_membership_history)
    {
        if ((int) $id_membership_history <= 0) {
            return;
        }

        $sql = '
            SELECT `id_customer`,`id_order`,`id_product`, date_start, expiry_date, TIMESTAMPDIFF(SECOND, CURRENT_TIMESTAMP, expiry_date) timediff1, TIMESTAMPDIFF(SECOND,date_start, expiry_date) timediff2
            FROM `' . _DB_PREFIX_ . 'sellerinfo_membership_history`
            WHERE IFNULL(is_cancelled,0) = 0 AND id_membership_history = ' . (int) $id_membership_history;
        $result = \Db::getInstance()->getRow($sql);

        if (!$result) {
            $sql = '
                SELECT `id_customer`,`id_order`,`id_product`, date_start, expiry_date, TIMESTAMPDIFF(SECOND, CURRENT_TIMESTAMP, expiry_date) timediff1, TIMESTAMPDIFF(SECOND,date_start, expiry_date) timediff2
                FROM `' . _DB_PREFIX_ . 'sellerinfo_membership_history`
                WHERE IFNULL(is_cancelled,0) = 2 AND id_membership_history = ' . (int) $id_membership_history;
            $result = \Db::getInstance()->getRow($sql);
        }

        $id_customer = (int) $result['id_customer'];
        $timediff = min((int) $result['timediff1'], (int) $result['timediff2']);
        $expiry_date = $result['expiry_date'];
        $date_start = $result['date_start'];
        $id_order = $result['id_order'];
        $id_product = $result['id_product'];

        $cartrule = \CartRule::getIdByCode('MEMCAN_' . $id_membership_history . '_' . $id_order);

        if ($cartrule) {
            return;
        }

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_membership_history` SET is_cancelled=1, date_cancelled=\'' . date('y-m-d H:i:s') . '\' WHERE id_membership_history=' . (int) $id_membership_history;
        \Db::getInstance()->Execute($sql);

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'sellerinfo_membership_history` SET date_start=DATE_ADD(date_start , INTERVAL -1*' . (int) $timediff . ' SECOND ),  expiry_date=DATE_ADD(expiry_date , INTERVAL -1*' . (int) $timediff . ' SECOND ) WHERE id_customer=' . (int) $id_customer . ' AND date_start>=\'' . pSQL($expiry_date) . '\'';
        \Db::getInstance()->Execute($sql);

        $this->updateEffectiveMembershipGroup($id_customer);
    }
}
