<?php


class PaymentSystem
{

    protected $input;

    protected $SMS;
    protected $DAL;
    protected $crypter;
    protected $ID;

    /*
        public function PaymentSystem(SendMessage $SMS, DAL $DAL, crypter $crypter)
        {
            $this->SMS = $SMS;
            $this->crypter = $crypter;
            $this->DAL = $DAL;
        }*/


    public function __construct(SendMessage $SMS, DAL $DAL, Crypter $crypter)
    {
        $this->SMS = $SMS;
        $this->crypter = $crypter;
        $this->DAL = $DAL;
    }

    public function Set($input)
    {
        $this->input = $input;
        $this->CreateLog($input, -1);
        return $this;
    }

    public function Run()
    {
        $out = $this->OutputData($this->Proxy($this->input));
        $this->CreateLog($out, $this->ID);
    }

    public function error($error)
    {
        echo 404 . $error;
    }

    protected function CreateLog($input, $id = -1)
    {
        if (is_array($input)) $input = json_encode($input, JSON_UNESCAPED_UNICODE);
        if ($id == -1) {
            $this->ID = $this->DAL->cDoCommandID("INSERT INTO app_wallet_operation_log (`user`, `input`) VALUE (? ,?)", array('s' => $this->getUserIP()), array('s' => $input));
            $state = ($this->ID > 0);
        } else {
            $state = $this->DAL->cDoCommand("UPDATE app_wallet_operation_log SET `output`=? WHERE `ID`=? ", array('s' => $input), array('i' => $id));
        }
        return $state;
    }

    protected function getUserIP()
    {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];
        elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        else $ip = $_SERVER['REMOTE_ADDR'];
        return $ip;
    }

    protected function InputDecoder($input)
    {
        $input = $this->crypter->SwipeString($input);
        $input = $this->crypter->hex2ByteArray($input);
        $input = $this->crypter->byteArray2String($input);
        return $input;
    }

    protected function OutputDecoder($output)
    {
        if (!is_string($output)) $output = json_encode($output, JSON_UNESCAPED_UNICODE);
        $output = $this->crypter->string2ByteArray($output);
        $output = $this->crypter->byteArray2Hex($output);
        $output = $this->crypter->SwipeString($output);
        return $output;
    }

    protected function OutputData($data)
    {
//        if (!is_string($data)) $data = enc($data, false);
        ob_clean();
        ob_end_clean();
        ob_start();
        $time = time();
        $return = array(
            'id' => $time . '-' . uniqid(),
            'user' => $this->OutputDecoder($this->getUserIP()),
            'server-time' => date("h:i:s", $time),
            'type' => $_SERVER['REQUEST_METHOD'],
            'response' => $data /*$this->OutputDecoder($data) */

        );
        print_r(json_encode($return, JSON_UNESCAPED_UNICODE));
        $out = ob_get_clean();
        ob_flush();
        flush();
        echo $out;
        return $out;
    }


    /*body system function*/

    public function ValidateRequest($count, $request)
    {
        if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? true : false)) {
            if (count($request) === $count) {
                $query = "";
                for ($i = 0; $i < (count($request) - 1); $i += 1) $query .= $request[$i];
                if (strlen($query) > 0) return $this->crypter->SwipeString(md5($count . $query)) === $request[$count - 1];
            }
        }
        return false;
    }

    protected function Proxy($args)
    {
        $out = null;
        switch ($this->InputDecoder($args[0])) {
            case 'send':
                $out = $this->function_Send($this->InputDecoder($args[1]));
                //$out = $this->function_WalletCreation($out['profile']);
                break;
            case 'send-transaction-to'://tayyed moshakhasate girande
                $out = $this->function_SendTransactionTo($this->InputDecoder($args[1]));
                break;
            case 'conform-transaction-send-sms':
                $out = $this->function_ConformTransactionSendSMS($this->InputDecoder($args[1]));
                break;
            case 'conform-transaction-send-sms-validation':
                $out = $this->function_ConformTransactionSendSMSValidation($this->InputDecoder($args[1]));
                break;

            case 'transaction-report-function':
                $out = $this->function_TransactionReport($this->InputDecoder($args[1]));
                break;

            case'wallet-balance':
                $out = $this->function_WalletBalance($this->InputDecoder($args[1]));
                break;
            case 'create-wallet':
                $out = $this->function_WalletCreation($this->InputDecoder($args[1]));
                break;
            default:
                $out = null;
                break;
        }
        return $out;
    }


    /*functions*/

    /*
     * send function
     * code : 3756e646
     *
     * args array  = (from,nonce,price)
     *
     * */
    protected function function_Send($args)
    {
        $object = (is_string($args) ? json_decode($args, true) : $args);
        $output = array(
            'error' => '0000',
            'status' => false
        );

        $transaction = array(
            'from' => $object['from'],
            'to' => $object['nonce'],
            'price' => $object['price']
        );

        if (is_numeric($transaction['price']) AND $transaction['price'] > 0) {
            if ($transaction['from'] !== $transaction['to']) {
                $transaction['f-w-id'] = $this->WalletID($transaction['from'], false);
                $transaction['t-w-id'] = $this->WalletID($transaction['to'], false);

//            $output['input'] = $transaction;

                if ($transaction['f-w-id'] AND $transaction['f-w-id'] != -1 AND $this->WalletValidation($transaction['from'], $transaction['f-w-id'], false)) {
                    if ($transaction['t-w-id'] AND $transaction['t-w-id'] != -1 AND $this->WalletValidation($transaction['to'], $transaction['t-w-id'], false)) {
                        if ($this->WalletAvailableBalance($transaction['from'], (int)$transaction['price'])) {
                            if ($this->WalletReduce($transaction['from'], $transaction['f-w-id'], $transaction['price'])) {
                                if ($this->WalletDeposit($transaction['to'], $transaction['t-w-id'], $transaction['price'])) {
                                    $output['status'] = true;
                                } else {
                                    //error handling
                                    $output['error'] = "مبلغ به حساب شما اضافه نشد.";
                                }
                            } else {
                                //error handling
                                $output['error'] = "مبلغ از حساب شما کسر نشد.";
                            }
                        } else {
                            //error handling
                            $output['error'] = "مبلغ درخواستی بیش از حساب شماست.";
                        }
                    } else {
                        //error handling
                        $output['error'] = "کیف پول مقصد یافت نشد.";
                    }
                } else {
                    //error handling
                    $output['error'] = "کیف پول کاربری یافت نشد.";
                }
            } else {
                //error handling
                $output['error'] = "شما نمی توانید به حساب خودتان انتقال دهید.";
            }
        } else {
            //error handle
            $output['log'] = "مبلغ ورودی قابل قبول نیست.";
        }
        return $output;
    }

    /*
     * sakht valet jadid
     * code : 362756164756
     *
     * */
    protected function function_WalletCreation($profile_id)
    {
//        $object = json_decode($args, true);

        $output = array(
            'error' => '',
            'wallet' => -1,
            'status' => false,
        );
//        $profile_id = $object ['for'];
        if (isset($profile_id) AND $this->WalletID($profile_id, false, false) AND $this->WalletID($profile_id, false, false) != -1) {
            $output['wallet'] = $this->WalletID($profile_id, false, false);
            $output['status'] = true;
        } else {
            $insert = $this->DAL->cDoCommandID(
                "INSERT INTO `app_wallet` (`profile_id_hash`) VALUES(?)", array('s' => md5("$profile_id"))
            );
            if ($insert) {
                $output['wallet'] = $insert;
                $output['status'] = true;
            }
        }
        return $output;
    }

    /*
     * code :
     * ersal  moshakhasat karbari
     *
     *
     * */
    protected function function_SendTransactionTo($args)
    {
        $object = json_decode($args, true);
        $transaction = array(
            'from' => $object['from'],
            'w-from' => '',
            'to' => $object['nonce'],
            'w-to' => '',
            'price' => $object['price'],
            'transaction' => uniqid()
        );


        $output = array(
            'error' => true,
            'log' => '',
            'client' => array(
                'price' => -1,
                'full-name' => '',
            ),
            'transaction-id' => ''
        );

        if (is_numeric($transaction['price']) AND $transaction['price'] > 0) {

            $transaction['w-from'] = $this->WalletID($transaction['from'], false);
            $transaction['w-to'] = $this->WalletID($transaction['to'], false);
            if ($this->WalletValidation($transaction['from'], $transaction['w-from'], false)) {
                if ($this->WalletValidation($transaction['to'], $transaction['w-to'], false)) {
                    $client = $this->DAL->cSelect("SELECT CONCAT(`fName`,' ',`lName`) as `full-name` FROM `app_acceptor_profile` WHERE `ID`=?", array('i' => $transaction['to']))[0];


                    $output['client']['price'] = "{$transaction['price']}";
                    $output['client']['full-name'] = $client['full-name'];
                    if (is_numeric($transaction['price'])) {
                        $trID = $this->WalletTransactionLog($transaction);
                        if ($trID && $trID > 0 && $trID != -1) {
                            $output['transaction-id'] = md5($trID);
                            $output['error'] = false;
                        } else {
                            $output['log'] = "خطایی رخ داده بعدا تلاش نمایید.";
                        }
                    } else {
                        $output['log'] = "مقدار قابل قبول نیست.";
                    }
                } else {
                    //error handle
                    $output['log'] = "حساب گیرنده یافت نشد.";
                }
            } else {
                //error handle
                $output['log'] = "حساب فرستنده یافت نشد.";
            }
        } else {
            //error handle
            $output['log'] = "مبلغ ورودی قابل قبول نیست.";
        }

        return $output;
    }

    protected function function_ConformTransactionSendSMS($args)
    {
        $object = json_decode($args, true);
        $transaction = array(
            'error' => true,
            'log' => '',
            'id' => $object['transaction'],
            'sms' => false
        );
        if (strlen($transaction['id']) > 0) {
            $trans = $this->DAL->cSelect("SELECT `sms`, `sender_profile_id_hash` FROM `app_wallet_transaction` WHERE md5(`ID`)=? AND `sms_conform_time` IS NULL",
                array('s' => $transaction['id'])
            );
            $transaction['log'] = $trans;
            if ($trans && count($trans) === 1) {
                $trans = $trans[0];
                $sms = $this->WalletSendSmsConform($trans['sms'], $trans['sender_profile_id_hash']);
                if (!$sms['error'] && is_numeric($sms['sms']) && strlen($sms['sms']) > 0) {
                    $transaction['error'] = false;
                    $transaction['sms'] = true;
                }
                $transaction['log'] = $sms['log'];
            } else {
                $transaction['log'] = 'تراکنش یافت نشد.';
            }
        } else {
            $transaction['log'] = 'تراکنش یافت نشد.';
        }
        return $transaction;
    }

    protected function function_ConformTransactionSendSMSValidation($args)
    {
        $object = json_decode($args, true);
        $transaction = array(
            'error' => true,
            'log' => '',
            'transaction' => $object['transaction'],
            'sms' => $object['sms'],
        );

        $trance = $this->DAL->cSelect("SELECT `sender_profile_id_hash`, `receiver_profile_id_hash`, `amount`, `sms` FROM `app_wallet_transaction` WHERE md5(`ID`)=? AND `sms_conform_time` IS NULL AND `sms_conform`=''",
            array('s' => $transaction['transaction'])
        );

        if ($trance && count($trance) === 1) {
            $trance = $trance[0];
            $param = array(
                'from' => $this->WalletClientID($trance['sender_profile_id_hash']),
                'nonce' => $this->WalletClientID($trance['receiver_profile_id_hash']),
                'price' => $trance['amount']
            );
            if ($transaction['sms'] === $trance['sms'] AND strlen($trance['sms']) > 0) {
                if ($this->DAL->cDoCommand("UPDATE `app_wallet_transaction` SET `sms_conform`=?, `sms_conform_time`=current_timestamp WHERE `sms`=? AND md5(`ID`)=? AND `sms_conform_time` IS NULL AND `sms_conform`=''",
                    array('s' => md5($transaction['sms'])),
                    array('s' => $transaction['sms']),
                    array('s' => $transaction['transaction'])
                )) {
                    $traceSend = $this->function_Send($param);

                    if ($traceSend["error"] === "0000" AND $traceSend['status'] === true) $transaction['error'] = false;
                    else $transaction['log'] = $traceSend['error'];
                    $this->DAL->cDoCommand("UPDATE `app_wallet_transaction` SET `description`=? WHERE md5(`ID`)=?",
                        array('s' => $traceSend["error"]),
                        array('s' => $transaction['transaction'])
                    );

                } else {
                    $transaction['log'] = 'کد وارد شده معتبر نمی باشد.';
                }
            } else {
                $transaction['log'] = 'کد وارد شده معتبر نمی باشد.';
            }
        } else {
            $transaction['log'] = 'پرداخت یافت نشد.';
        }

        return $transaction;
    }


    protected function function_TransactionReport($args)
    {
        $object = json_decode($args, true);

        $receiver = $this->DAL->cSelect("SELECT IF(`description` LIKE '0000','TRUE','FALSE') as `status`, `transaction_time` as `time` ,'receiver' as `mode`, `amount` as `price` , (SELECT CONCAT(`fName`,' ',`lName`) FROM `app_acceptor_profile` WHERE md5(`ID`) LIKE `sender_profile_id_hash`) as `receiver` FROM `app_wallet_transaction` WHERE `receiver_profile_id_hash`=md5(?) ORDER BY `transaction_time` DESC ",
            array('s' => $object['for'])
        );

        $sends = $this->DAL->cSelect("SELECT IF(`description` LIKE '0000','TRUE','FALSE') as `status`, `transaction_time` as `time` ,'send' as `mode`, `amount` as `price` , (SELECT CONCAT(`fName`,' ',`lName`) FROM `app_acceptor_profile` WHERE md5(`ID`) LIKE `receiver_profile_id_hash`) as `receiver` FROM `app_wallet_transaction` WHERE `sender_profile_id_hash`=md5(?) ORDER BY `transaction_time` DESC ",
            array('s' => $object['for'])
        );

        $transaction = array(
            'error' => true,
            'log' => '',
            'transactions' => array_merge(($receiver ? $receiver : array()), ($sends ? $sends : array()))
        );
        $transaction['error'] = false;
        return $transaction;
    }


    protected function function_WalletBalance($args)
    {
        $object = json_decode($args, true);
////        $wallet = $this->WalletBalance($object['cc']);
//        return $wallet;
        if ($this->function_WalletCreation($object['cc'])['status']) {
            $wallet = $this->WalletBalance($object['cc'], false);
        } else {
            $wallet = array('error' => true, 'log' => 'ولت ساخته نشد.', 'isLock' => false, 'amount' => -1);

        }

        return $wallet;
    }


    /*functions*/


    /*
     * gereftan id wallet faal
     * */
    protected function WalletID($profile_id_hash, $isHash = false, $active = true)
    {
        if (isset($profile_id_hash)) {
            if (!$isHash) $profile_id_hash = md5($profile_id_hash);
            if ($active) $active = " AND status=true;";
            else $active = '';
            $wallet = $this->DAL->cSelect("SELECT `ID` as `wallet` FROM app_wallet WHERE `profile_id_hash`=? " . $active, array('s' => $profile_id_hash));
            return (($wallet) == (count($wallet) === 1) ? $wallet[0]['wallet'] : -1);
        }
        return -1;
    }

    /*
     * gereftan mablagh dakhele hesab
     * * */
    protected function WalletBalance($profile_id_hash, $isHash = false)
    {
        $output = array('error' => true, 'log' => '', 'isLock' => false, 'amount' => -1);
        if (isset($profile_id_hash)) {
            if (!$isHash) $profile_id_hash = md5($profile_id_hash);
            $wallet = $this->DAL->cSelect("SELECT `balance`,IF(`status`,'1','0') as `status` FROM `app_wallet` WHERE `profile_id_hash`=?", array('s' => $profile_id_hash));
            if ($wallet AND count($wallet) == 1) {
                $output['error'] = false;

                $output['amount'] = "" . (int)$wallet[0]['balance'];
                if ($wallet[0]['status'] === '1') {
                    $output['isLock'] = false;
                } else {
                    $output['isLock'] = true;
                    $output['log'] = 'حساب غیر فعال است.';
                }
            } else {
                $output['log'] = 'کیف پول یافت نشد.';
            }
        } else {
            $output['log'] = 'کاربری یافت نشد.';
        }
        return $output;
    }

    /*
     * barecy vojode mablagh dar hesab
     * */
    protected function WalletAvailableBalance($profile_id_hash, $balance, $isHash = false)
    {
        if (isset($profile_id_hash)) {
            if (!$isHash) $profile_id_hash = md5($profile_id_hash);
            $wallet = $this->DAL->cSelect("SELECT (true) as state FROM app_wallet WHERE `profile_id_hash`=? AND status=true AND `balance`>=?", array('s' => $profile_id_hash), array('i' => $balance));
            if (count($wallet) == 1) {
                return $wallet[0]['state'];
            }
        }
        return false;
    }

    /*
     * tayyed vojode wallet karbari
     *
     * */
    protected function WalletValidation($profile_id_hash, $wallet_id_hash, $isHash = false)
    {
        // $this->DAL-> //
        // tootla by

        // majmoe kole daryafti ha +
        // majmoe kole pardakhti ha+
        // majmoe kole ersal ha
        //  -
        // majmoe kole kharid ha +
        // majmoe kole ersal ha +
        // balance
        // = 0
        if (isset($profile_id_hash) AND isset($wallet_id_hash)) {
            if (!$isHash) $profile_id_hash = md5($profile_id_hash);
            if (!$isHash) $wallet_id_hash = md5($wallet_id_hash);
            $wallet = $this->DAL->cSelect("SELECT md5(`ID`) as `wallet` FROM app_wallet WHERE `profile_id_hash`=? AND md5(`ID`)=? AND status=true", array('s' => $profile_id_hash), array('s' => $wallet_id_hash));
            return ($wallet AND count($wallet) == 1 ? $wallet[0]['wallet'] : false);
        }
        return false;
    }

    /*
       * kam kardan az hesab + ezafe kardan log
       * param profile_id id karbary
       * param wallet_id id wallet
       * param amount mablaghe
       *
       * */
    protected function WalletReduce($profile_id, $wallet_id, $amount)
    {
        if ($this->WalletValidation($profile_id, $wallet_id) AND is_numeric($amount) AND $amount > 0) {
            if ($this->WalletAvailableBalance($profile_id, $amount)) {

                $wallet_amount = $this->WalletBalance($profile_id, false);
                if (!$wallet_amount['error'] && !$wallet_amount['isLock']) {

                    $ID = $this->DAL->cDoCommandID(
                        "INSERT INTO `app_wallet_services_log` (profile_id_hash, wallet_id_hash, description, before_balance, mode, status) VALUES (?, ?, ?, ?, 'unknown', false);",
                        array('s' => md5($profile_id)),
                        array('s' => md5($wallet_id)),
                        array('s' => $amount),
                        array('s' => $wallet_amount['amount'])
                    );

                    if ($ID && $ID > 0) {
                        if ($this->DAL->cDoCommand(
                            "UPDATE `app_wallet` SET `balance`=(`balance`-?) WHERE `profile_id_hash`=?;",
                            array('i' => $amount),
                            array('s' => md5($profile_id)))) {
                            return $this->DAL->cDoCommand(
                                "UPDATE `app_wallet_services_log` SET `after_balance`=?, `mode`=('reduce'), `status`=true WHERE `ID`=?;",
                                array('i' => ((int)$wallet_amount['amount']) - ((int)$amount)),
                                array('i' => $ID)
                            );
                        }
                    }
                }
            }
        }

        return false;
    }

    /*
     * ezafe kardan be hesab + ezafe kardan log
     * param profile_id id karbary
     * param wallet_id id wallet
     * param amount mablaghe
     *
     * */
    protected function WalletDeposit($profile_id, $wallet_id, $amount)
    {
        if ($this->WalletValidation($profile_id, $wallet_id) AND is_numeric($amount) AND $amount > 0) {

            $wallet_amount = $this->WalletBalance($profile_id, false);
            if (!$wallet_amount['error'] && !$wallet_amount['isLock']) {

                $ID = $this->DAL->cDoCommandID(
                    "INSERT INTO `app_wallet_services_log` (profile_id_hash, wallet_id_hash, description, before_balance, mode, status) VALUES (?, ?, ?, ?, 'unknown', false);",
                    array('s' => md5($profile_id)),
                    array('s' => md5($wallet_id)),
                    array('s' => $amount),
                    array('s' => $wallet_amount['amount'])
                );

                if ($ID && $ID > 0) {
                    if ($this->DAL->cDoCommand(
                        "UPDATE `app_wallet` SET `balance`=(`balance`+?) WHERE `profile_id_hash`=?;",
                        array('i' => $amount),
                        array('s' => md5($profile_id)))) {
                        return $this->DAL->cDoCommand(
                            "UPDATE `app_wallet_services_log` SET `after_balance`=?, `mode`=('deposit'), `status`=true WHERE `ID`=?;",
                            array('i' => ((int)$wallet_amount['amount']) + ((int)$amount)),
                            array('i' => $ID));
                    }
                }
            }
        }

        return false;
    }

    /*
     *
     * creat complete transaction
     *
     * */
    protected function WalletTransactionLog($transaction)
    {
        $trID = $this->DAL->cDoCommandID("INSERT INTO `app_wallet_transaction` (`transaction_id`,`sender_profile_id_hash`,`receiver_profile_id_hash`,`amount`,`sms`,`sms_conform`) VALUES (?,?,?,?,?,?)",
            array('s' => $transaction['transaction']),
            array('s' => md5($transaction['from'])),
            array('s' => md5($transaction['to'])),

            array('i' => $transaction['price']),
            array('s' => mt_rand(111111, 999999)),
            array('s' => '')
        );
        if ($trID && $trID > 0) {
            return $trID;
        } else return -1;
    }

    /*client id*/
    protected function WalletClientID($profile_hash)
    {
        $client = $this->DAL->cSelect("SELECT `ID` FROM `app_acceptor_profile` WHERE md5(`ID`)=?",
            array('s' => $profile_hash)
        );

        if ($client && count($client) === 1) {
            if ((int)$client[0]['ID'] > 0) return (int)$client[0]['ID'];
        }

        return $client;
    }

    /*wallet send sms*/

    protected function WalletSendSmsConform($sms, $profile_hash)
    {
        $output = array(
            'error' => true,
            'log' => '',
            'sms' => ''
        );
        if (strlen($sms) > 0 && is_numeric($sms)) {
            if (strlen($profile_hash)) {
                $profile = $this->DAL->cSelect("SELECT `pNumber` FROM `app_acceptor_profile` WHERE md5(`ID`)=?",
                    array('s' => $profile_hash)
                );
                if ($profile && count($profile) === 1) {
                    $profile = $profile[0]['pNumber'];
                    if (is_numeric($profile) && (strlen($profile) === 11 OR strlen($profile) === 10) && strlen((int)$profile) === 10) {
                        $output['error'] = false;
                        $output['sms'] = $this->SMS->SendOneMessage($profile, $sms);
                    } else {
                        $output['log'] = 'شماره مبایل فرستنده یافت نشد.';
                    }
                } else {
                    $output['log'] = 'کاربری یافت نشد.';
                }
            } else {
                $output['log'] = 'کاربری یافت نشد.';
            }
        } else {
            $output['log'] = 'کد یافت نشد.';
        }

        return $output;
    }


    /*body system function*/


}

/*body system function*/