<?php

/**
 * Class ControllerExtensionPaymentTrustPayCP
 *
 * The OpenCart extension for finby payment gateway API v2.
 * Card payments.
 * Catalog controller.
 * https://doc.finby.com/v02
 *
 * @copyright  2019 finby
 * @author     finby
 * @link       https://www.finby.com
 */
class ControllerExtensionPaymentTrustPayCP extends Controller {
    protected $trustpay_config;

	public function index() {
		$this->load->language('extension/payment/trustpay_cp');

        $data['text_license'] = sprintf($this->language->get('text_license'), date("Y"));
        
        $this->loadConfiguration();

        $action_url = $this->trustpay_config['api_merchant_portal']['live'];
        
        $data['button_confirm'] = $this->language->get('button_confirm');

		$this->load->model('checkout/order');

		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
		
		if ($order_info) {
            $amount = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false);

            if($order_info['currency_code'] == "HUF") {
                //  For the currency HUF remember to use only integer amounts in payment requests (but they still have to be formatted with exactly two decimal places, e.g. 1234.00)
                $amount = number_format(floor($amount), 2, '.', '');
            } else {
                // Formatted with exactly 2 decimal places
                $amount = number_format($order_info['total'] * $order_info['currency_value'], 2, '.', '');
            }

            $post_data = array(
                "AccountId" => $this->config->get('trustpay_cp_aid'),
                "Amount" => $amount,
                "Currency" => $order_info['currency_code'],
                "Reference" => $this->session->data['order_id'],
                "PaymentType" => 0, // For purchase must be set to 0 https://doc.trustpay.eu/v02#cards-purchase
                "BillingCity" => $order_info['payment_city'],
                "BillingCountry" => $order_info['payment_iso_code_2'],
                "BillingPostcode" => $order_info['payment_postcode'],
                "BillingStreet" => $order_info['payment_address_1'],
                "CardHolder" => $order_info['firstname'] . ' ' . $order_info['lastname'],
                "Email" => $order_info['email']
            );

            $missing_values = array_filter($post_data, function($val) {
                return $val === '';
            });

            $to_sign = implode("/", $post_data);
            $signature = $this->getSignature($this->config->get('trustpay_cp_key'), $to_sign);
            $post_data['Signature'] = $signature;

            $post_data['Url'] = $this->url->link($this->trustpay_config['routes']['cancel'], '', true);
            $post_data['ReturnUrl'] = $this->url->link($this->trustpay_config['routes']['success'], '', true);
            $post_data['CancelUrl'] = $this->url->link($this->trustpay_config['routes']['cancel'], '', true);
            $post_data['ErrorUrl'] = $this->url->link($this->trustpay_config['routes']['error'], '', true);
            $post_data['NotificationUrl'] = $this->url->link($this->trustpay_config['routes']['notification'], '', true);
            $post_data['Localization'] = substr($this->session->data['language'], 0, 2);
            $post_data['Country'] = $order_info['payment_iso_code_2'];
            $post_data['Description'] = $this->language->get('text_description') . $this->session->data['order_id'];
            $post_data['PluginVersion'] = 'opencart23-3.3.4';

            // Fix for Journal checkout
            if(empty($missing_values)) {
                $action_url .= '?';
                $action_url .= http_build_query($post_data);
            }

            $data['action_url'] = $action_url;

            $debug_params = http_build_query($post_data);
            $data['debug_url'] = $this->url->link($this->trustpay_config['routes']['debug'], $debug_params, true);

            return $this->load->view('extension/payment/trustpay_cp', $data);
		}
	}

    private function loadConfiguration() {
        $this->trustpay_config = unserialize($this->config->get('trustpay_cp_config'));
    }

    private function getSignature($secret_key, $message) {
        return strtoupper(hash_hmac('sha256', pack('A*', $message), pack('A*', $secret_key)));
    }

    public function success() {
	    if (isset($this->session->data['order_id']) && isset($this->request->get['Reference']) && isset($this->request->get['ResultCode'])){
            $order_id = $this->session->data['order_id'];
            $reference = $this->request->get['Reference'];
            $result = $this->request->get['ResultCode'];
            $acq_result = isset($this->request->get['AcquirerResponseId']) ? $this->request->get['AcquirerResponseId'] : '';
            $payment_request_id = isset($this->request->get['PaymentRequestId']) ? $this->request->get['PaymentRequestId'] : '';

            if ($order_id == $reference) {
                $this->load->model('checkout/order');

                $order_info = $this->model_checkout_order->getOrder($order_id);

                if ($order_info && $order_info['order_status_id'] == 0) {
                    $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('trustpay_cp_pending_status_id'));

                    if ($this->config->get('trustpay_cp_debug')) {
                        $this->log->write('Trust Pay :: CONFIRM: Order ID = ' . $order_id . '; Result Code = ' . $result . '; Card acquirer result code = ' . $acq_result . '; Payment request ID = ' . $payment_request_id);
                    }
                }
            }
        }

        header("Location: " . $this->url->link('checkout/success'));
        die();
    }

    public function error() {
        $reference = isset($this->request->get['Reference']) ? $this->request->get['Reference'] : '';
        $result = isset($this->request->get['ResultCode']) ? $this->request->get['ResultCode'] : '';
        $acq_result = isset($this->request->get['AcquirerResponseId']) ? $this->request->get['AcquirerResponseId'] : '';
        $payment_request_id = isset($this->request->get['PaymentRequestId']) ? $this->request->get['PaymentRequestId'] : '';

        $this->log->write('Trust Pay :: WARNING: Payment failed! Order ID = ' . $reference . '; Result code = ' . $result . '; Card acquirer result code = ' . $acq_result . '; Payment request ID = ' . $payment_request_id);

        $this->language->load('extension/payment/trustpay_cp');

        $this->session->data['error'] = sprintf($this->language->get('error_payment'), $result);

        header("Location: " . $this->url->link('checkout/checkout'));
        die();
    }

	public function callback() {
		if ($this->config->get('trustpay_cp_debug')) {
            $this->log->write('Trust Pay :: CALLBACK: ' . http_build_query($this->request->get));
		}

        $required_parameters = array(
            'AccountId',
            'Amount',
            'Currency',
            'Reference',
            'Type',
            'ResultCode',
            'Signature'
        );

        $missing_parameters = false;

        foreach ($required_parameters as $required_parameter) {
            if (!isset($this->request->get[$required_parameter])) {
                $missing_parameters = true;
                break;
            }
        }
		
		if ($this->config->get('trustpay_cp_status') && !$missing_parameters) {
            $order_id = $this->request->get['Reference'];
            $result = (int)$this->request->get['ResultCode'];

			$this->load->model('checkout/order');

			$order_info = $this->model_checkout_order->getOrder($order_id);

			if ($order_info) {
                $to_sign = array(
                    'AccountId' => $this->request->get['AccountId'],
                    'Amount' => $this->request->get['Amount'],
                    'Currency' => $this->request->get['Currency'],
                    'Reference' => $this->request->get['Reference'],
                    'Type' => $this->request->get['Type'],
                    'ResultCode' => $this->request->get['ResultCode']
                );

                if (isset($this->request->get['PaymentRequestId']) && $this->request->get['PaymentRequestId'] != '') {
                    $to_sign['PaymentRequestId'] = $this->request->get['PaymentRequestId'];
                }
                if (isset($this->request->get['CardID']) && $this->request->get['CardID'] != '') {
                    $to_sign['CardID'] = $this->request->get['CardID'];
                }
                if (isset($this->request->get['CardMask']) && $this->request->get['CardMask'] != '') {
                    $to_sign['CardMask'] = $this->request->get['CardMask'];
                }
                if (isset($this->request->get['CardExpiration']) && $this->request->get['CardExpiration'] != '') {
                    $to_sign['CardExpiration'] = $this->request->get['CardExpiration'];
                }
                if (isset($this->request->get['AuthNumber']) && $this->request->get['AuthNumber'] != '') {
                    $to_sign['AuthNumber'] = $this->request->get['AuthNumber'];
                }

                $to_sign = implode("/", $to_sign);

                $signature = $this->getSignature($this->config->get('trustpay_cp_key'), $to_sign);
				
				if (strcmp($signature, $this->request->get['Signature']) == 0 ) {
					$order_status_id = $this->config->get('config_order_status_id');

                    if ($result == 0) {
                        $amt_match = ((float)$this->request->get['Amount'] == number_format($this->currency->format($order_info['total'], $order_info['currency_code'], false, false), 2, '.', ''));

                        if ($amt_match) {
                            $order_status_id = $this->config->get('trustpay_cp_success_status_id');
                        } else {
                            $order_status_id = $this->config->get('trustpay_cp_amount_mismatch_status_id');

                            if ($this->config->get('trustpay_cp_debug')) {
                                $this->log->write('Trust Pay :: WARNING: Signature or Amount mismatch! ' . $this->request->get['Amount'] . ' vs. ' . number_format($this->currency->format($order_info['total'], $order_info['currency_code'], false, false), 2, '.', '') . '; Order ID = ' . $order_id);
                            }
                        }
                    } elseif ($result == 1) {
                        $order_status_id = $this->config->get('trustpay_cp_pending_status_id');
                    } elseif ($result == 2) {
                        $order_status_id = $this->config->get('trustpay_cp_announced_status_id');
                    } elseif ($result == 3) {
                        $order_status_id = $this->config->get('trustpay_cp_authorized_status_id');
                    } elseif ($result == 4) {;
                        $order_status_id = $this->config->get('trustpay_cp_processing_status_id');
                    } elseif ($result == 5 || $result >= 1000) {
                        $order_status_id = $this->config->get('trustpay_cp_failed_status_id');
                    }
					
					// Place order first.
					if ($order_info['order_status_id'] == 0) {
						$this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id'));
						
						if ($this->config->get('trustpay_cp_debug')) {
                            $this->log->write('Trust Pay :: CONFIRM: Order ID = ' . $order_id);
						}
					}
					
					// Update order history if order status is not complete and notify customer.
					if ($order_info['order_status_id'] !=  $this->config->get('config_complete_status_id')) {
						$notify = $this->config->get('trustpay_cp_notify') ? true : false;
						
						$this->model_checkout_order->addOrderHistory($order_id, $order_status_id, '', $notify);
						if ($this->config->get('trustpay_cp_debug')) {
                            $this->log->write('Trust Pay :: UPDATE: Order ID = ' . $order_id . ' New Order Status ID = ' . $order_status_id);
						}
					} else {
                        $this->log->write('Trust Pay :: WARNING: Trying to edit completed order! Order ID = ' . $order_id . '; Result code = ' . $this->request->get['ResultCode']);
					}
				}
			}
		}
	}

    public function debug() {
        $this->loadConfiguration();
        
        $link =  $this->trustpay_config['api_merchant_portal']['live'] . '?';
        
        $link .= http_build_query($_GET);

	if ($this->config->get('trustpay_cp_debug')) {
            $this->log->write('Trust Pay :: CALL: ' . $link);
	}
	
        if ($this->config->get('trustpay_cp_test')) {
                echo '<a href="' . $link . '" target="_blank">' . $link . '</a>';
                echo '<pre>';
                print_r($_GET);
        }
    }
}
