<?php 
/**
 * @package    Proxim
 * @author     Davison Pro <davis@davisonpro.dev | https://davisonpro.dev>
 * @copyright  2019 Proxim
 * @version    1.5.0
 * @since      File available since Release 1.0.0
 */

namespace Proxim\Module;

use Db;
use Proxim\Application;
use Proxim\Configuration;
use Proxim\Currency;
use Proxim\Database\DbQuery;
use Proxim\Mail;
use Proxim\Order\AdditionalService;
use Proxim\Order\Order;
use Proxim\Preference\Deadline;
use Proxim\Site\Site;
use Proxim\Tools;
use Proxim\User\Customer;
use Proxim\User\Wallet as CustomerWallet;
use Proxim\User\Employee;
use Proxim\Util\ArrayUtils;
use Proxim\Util\DateUtils;
use Proxim\Validate;
use Wallet;

abstract class PaymentModule extends Module
{
    public $currencies = true;

    const DEBUG_MODE = false;

    /**
     * List all installed and active payment modules.
     *
     * @see Module::getPaymentModules() if you need a list of module
     *
     * @return array module informations
     */
    public static function getInstalledPaymentModules()
    {
        $hook_payment = 'Payment';
        if (Db::getInstance()->getValue('SELECT `hook_id` FROM ' .  Db::prefix('hook') . 's WHERE `name` = \'paymentOptions\'')) {
            $hook_payment = 'paymentOptions';
        }

        return Db::getInstance()->executeS('
            SELECT DISTINCT m.`module_id`, h.`hook_id`, m.`name`, hm.`position`
            FROM ' .  Db::prefix('module') . ' m
            LEFT JOIN ' .  Db::prefix('hook_module') . ' hm ON hm.`module_id` = m.`module_id`
            LEFT JOIN ' .  Db::prefix('hook') . ' h ON hm.`hook_id` = h.`hook_id`
            WHERE h.`name` = \'' . pSQL($hook_payment) . '\'
        ');
    }

    public static function processPayment($nodeId, $handle, $payload = array())
    {
        $app = Application::getInstance();

        switch( $handle ) { 
            
            case 'order':
                $order = new Order( (int) $nodeId );
                if (!Validate::isLoadedObject($order)) {
                    return false;
                } 

                $currency = $order->currency;

                $options['currency'] = array(
                    'symbol' => $currency->symbol,
                    'rate' => $currency->conversion_rate
                );

                $order->total_paid = $order->total_paid + $order->total;
                $old_status = $order->status_id;

                if ( 
                    $old_status == Order::FAKE || 
                    $old_status == Order::FREE_INQUIRY || 
                    $old_status == Order::INQUIRY
                ) {
                    $customer_deadline = time() + ($order->hrs_customer*60*60);
                    $writer_deadline = time() + ($order->hrs_writer*60*60);
                    $order->customer_deadline = DateUtils::date($customer_deadline);
                    $order->writer_deadline = DateUtils::date($writer_deadline);

                    if ($order->progressive_delivery) {
                        $order->status_id = Order::NEW_PAID;
                    } else {
                        $order->status_id = Order::ORDER_PUBLISHED;
                    }

                    $order->is_paid = 1;
                    $order->paid_at = DateUtils::now();
                }

                $order->update();

                if ( 
                    $old_status == Order::FAKE || 
                    $old_status == Order::FREE_INQUIRY || 
                    $old_status == Order::INQUIRY
                ) {
                    $customer = new Customer( (int) $order->customer_id );
                    if(Validate::isLoadedObject($customer)) {
                        $customer->total_spent = $customer->total_spent + $order->total;
                        $customer->update();

                        /** process affiliates */
                        if ( $customer->referrer_id && !$customer->affiliate_used ) {
                            $app->processAffiliates( $customer->id, $customer->referrer_id );
                        }

                        $site = new Site( (int) $customer->site_id );
                        if( Validate::isLoadedObject($site) ) {
                            $site->orders = $site->orders+1;       
                            $site->payments = $site->payments + $order->total;
                            $site->update();
                        }

                        try {
                            $mailParams = array(
                                'order_id' => $order->id,
                                'title' => $order->title,
                                'pages' => $order->pages,
                                'payment_method' => Tools::ucfirst($order->payment_method),
                                'paid_at' => DateUtils::date( strtotime($order->paid_at) , null, 'M jS, Y \\a\\t g:i A'),
                                'paid_amount' => formatPrice($order->total, $options),
                                'type' => 'order',
                                'admin_site_name' => Configuration::get('SITE_NAME', PROX_ADMIN_SITE_ID, null),
                                'admin_order_url' => Configuration::get('SITE_DOMAIN', PROX_ADMIN_SITE_ID, $app->base_uri) . '/order/' . (int) $order->id,
                                'order_url' => $app->base_uri . '/dashboard/order/' . (int) $order->id,
                            );

                            Mail::Send(
                                'payment',
                                'Payment confirmation for order #' . $order->id,
                                $mailParams,
                                $customer->email
                            );

                            $receivers = array();

                            $site_email = Configuration::get('SITE_EMAIL', PROX_ADMIN_SITE_ID);
                            if(!empty($site_email)) {
                                $receivers[] = $site_email;
                            }

                            $notification_emails = $app->getNotificationEmails();
                            $receivers = array_merge($receivers, $notification_emails);

                            $sql = new DbQuery();
                            $sql->select('e.email');
                            $sql->from('employee', 'e');
                            $sql->where('employee_group = ' . (int) Employee::GROUP_WRITER);
                            $sql->where('is_started = 1');
                            $sql->where('is_banned = 0');
                            $result = Db::getInstance(PROX_USE_SQL_SLAVE)->executeS($sql);

                            foreach ($result as $writer) {
                                if( ArrayUtils::has($writer, 'email') && Validate::isEmail(ArrayUtils::get($writer, 'email')) ) {
                                    $receivers[] = ArrayUtils::get($writer, 'email');
                                }
                            }

                            foreach ($receivers as $receiver) {
                                Mail::Send(
                                    'new_order',
                                    'New Order #' . $order->id . ' available',
                                    $mailParams,
                                    $receiver,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    PROX_ADMIN_SITE_ID
                                );
                            }
                        } catch(\Exception $e) {

                        }
                    }
                }

                return true;
                break;

            case 'add-payment':
                $addPayment = new AdditionalService( (int) $nodeId );
                if (!Validate::isLoadedObject($addPayment)) {
                    return false;
                } 
    
                $order = new Order( (int) $addPayment->order_id );
                if (!Validate::isLoadedObject($order)) {
                    return false;
                }

                if (!$addPayment->is_paid) {
                    // pages
                    if($addPayment->pages) $order->pages = $order->pages + $addPayment->pages;
    
                    // charts
                    if($addPayment->charts) $order->charts = $addPayment->charts + $addPayment->charts;
    
                    // slides
                    if($addPayment->slides) $order->slides = $addPayment->slides + $addPayment->slides;
    
                    // writer samples
                    if($addPayment->writer_samples) $order->writer_samples = 1;
    
                    // used sources
                    if($addPayment->used_sources) $order->used_sources = 1;
    
                    // expert proofreading
                    if($addPayment->expert_proofreading) $order->expert_proofreading = 1;
    
                    // progressive delivery
                    if($addPayment->progressive_delivery) $order->progressive_delivery = 1;
    
                    // writer category 
                    if($addPayment->writer_category_id) $order->writer_category_id = $addPayment->writer_category_id;
    
                    // shorten deadline
                    if($addPayment->tariff_id) {
                        $tariff = new Deadline($addPayment->tariff_id);
                        if ( Validate::isLoadedObject($tariff) ) {
                            $price_per_page = (float) $tariff->price_per_page;
                            $hrs_customer = (int) $tariff->hrs_customer;
                            $hrs_writer = (int) $tariff->hrs_writer;
                            $customer_deadline = time() + ($hrs_customer*60*60);
                            $writer_deadline = time() + ($hrs_writer*60*60);
    
                            $order->tariff_id = $addPayment->tariff_id;
                            $order->price_per_page = $price_per_page;
                            $order->hrs_customer = $hrs_customer;
                            $order->hrs_writer = $hrs_writer;
                            $order->customer_deadline = DateUtils::date($customer_deadline);
                            $order->writer_deadline = DateUtils::date($writer_deadline);
                        }
                    } 
    
                    $order->update();
    
                    $addPayment->is_paid = 1;
                    $addPayment->paid_at = DateUtils::now();
                    $addPayment->update();
    
                    $customer = new Customer( (int) $order->customer_id );
                    if(Validate::isLoadedObject($customer)) {
                        $customer->total_spent = $customer->total_spent + $addPayment->total;
                        $customer->update();
    
                        $site = new Site( (int) $customer->site_id );
                        if( Validate::isLoadedObject($site) ) {
                            $site->payments = $site->payments + $addPayment->total;
                            $site->update();
                        }
                    }
                }
    
                return true;
                break;

            case 'tip':
                $amount = (float) ArrayUtils::get($payload, 'amount');
                $payment_method = ArrayUtils::get($payload, 'payment_method');
                $currency_code = ArrayUtils::get($payload, 'currency'); 
                $transaction_id =ArrayUtils::get($payload, 'paymentId');

                $order = new Order( (int) $nodeId );
                if (!Validate::isLoadedObject($order)) {
                    return false;
                }

                $currencyId = Currency::getIdByIsoCode( $currency_code );
                $currency = Currency::getCurrencyInstance( (int) $currencyId);

                // check if transaction exists
                $query = new DbQuery();
                $query->select('order_tip_id');
                $query->from('order_tip');
                $query->where('transaction_id = \'' . pSQL($transaction_id) . '\'');
                $exists = Db::getInstance()->getValue($query);

                if(!$exists) {
                    $result = Db::getInstance()->insert(
                        'order_tip',
                        array(
                            'order_id' => $order->id,
                            'currency_id' => $currency->id,
                            'transaction_id' => $transaction_id, 
                            'payment_method' => $payment_method,
                            'amount' => $amount,
                            'date_add' => DateUtils::now(),
                        )
                    );

                    $writer_tip_amount = ($amount * Configuration::get('TIP_WRITER_PERCENT', PROX_ADMIN_SITE_ID)) / 100;
                    $editor_tip_amount = ($amount * Configuration::get('TIP_EDITOR_PERCENT', PROX_ADMIN_SITE_ID)) / 100;

                    if($writer_tip_amount > 0) {
                        $order->writer_pay = $order->writer_pay + $writer_tip_amount;
                    }

                    if($editor_tip_amount > 0) {
                        $order->editor_pay = $order->editor_pay + $editor_tip_amount;
                    }

                    $order->update();
                }


                break;

            case 'wallet':
                $amount = (float) ArrayUtils::get($payload, 'amount');
                $payment_method = ArrayUtils::get($payload, 'payment_method');
                $currency_code = ArrayUtils::get($payload, 'currency'); 
                $transaction_id =ArrayUtils::get($payload, 'paymentId');

                $customer = new Customer( (int) $nodeId );
                if (!Validate::isLoadedObject($customer)) {
                    return false;
                }

                $currencyId = Currency::getIdByIsoCode( $currency_code );
                $currency = Currency::getCurrencyInstance( (int) $currencyId);

                // check if transaction exists
                $query = new DbQuery();
                $query->select('wallet_transaction_id');
                $query->from('wallet_transaction');
                $query->where('transaction_id = \'' . pSQL($transaction_id) . '\'');
                $exists = Db::getInstance()->getValue($query);

                if(!$exists) {
                    $walletId = CustomerWallet::getIdByCustomerId( $customer->id );
                    if($walletId) {
                        $wallet = new CustomerWallet( (int) $walletId );
                    }
                    
                    if(
                        !isset($wallet) || 
                        !Validate::isLoadedObject($wallet)
                    ) {
                        $wallet = new CustomerWallet();
                        $wallet->customer_id = $customer->id;
                        $wallet->wallet_balance = 0;
                        $wallet->add();
                    }

                    $result = Db::getInstance()->insert(
                        'wallet_transaction',
                        array(
                            'wallet_id' => $wallet->id,
                            'currency_id' => $currency->id,
                            'transaction_id' => $transaction_id, 
                            'source' => 'deposit',
                            'payment_method' => $payment_method,
                            'amount' => $amount,
                            'date_add' => DateUtils::now(),
                        )
                    );

                    if(!$result) {
                        return false;
                    }

                    $wallet->wallet_balance = $wallet->wallet_balance + $amount;
                    $wallet->update();
                }

                return true;
                break;
    
            default:
                return false;
                break;
        }
    }
}