<?php

require_once DIR_SYSTEM . 'library/PagSeguro/PagSeguroData.class.php';
require_once DIR_SYSTEM . 'library/PagSeguroLibrary/PagSeguroLibrary.php';
require_once DIR_SYSTEM . 'library/PagSeguroLibrary/utils/PagSeguroHttpConnection.class.php';
require_once DIR_SYSTEM . 'library/PagSeguroLibrary/utils/PagSeguroXmlParser.class.php';

class ControllerPaymentPagseguroCreditCard extends Controller
{
	public function index()
	{
		$this->language->load('payment/pagseguro_credit_card');

		$this->load->model('checkout/order');
		$order_info = $this->model_checkout_order->getOrder((int)$this->session->data['order_id']);

		$data['nome_cartao']     = trim(trim($order_info['payment_firstname']) .' '. trim($order_info['payment_lastname']));
		$data['cpf']             = isset($order_info['custom_field']['cpf']) ? $order_info['custom_field']['cpf'] : '';
		$data['telefone']        = $order_info['telephone'];
		$data['data_nascimento'] = isset($order_info['custom_field']['nascimento']) ? $order_info['custom_field']['nascimento'] : '';
		$data['endereco']        = $order_info['payment_address_1'];
		$data['numero']          = isset($order_info['payment_custom_field']['numero']) ? $order_info['payment_custom_field']['numero'] : '';
		$data['complemento']     = isset($order_info['payment_custom_field']['complemento']) ? $order_info['payment_custom_field']['complemento'] : '';
		$data['bairro']          = $order_info['payment_address_2'];
		$data['cep']             = $order_info['payment_postcode'];
		$data['cidade']          = $order_info['payment_city'];
		$data['estado']          = $order_info['payment_zone_id'];
		$data['total']           = $order_info['total'];

		if ($data['data_nascimento'] == '0000-00-00') {
			$data['data_nascimento'] = '';
		} else {
			$data['data_nascimento'] = date('d/m/Y', strtotime($data['data_nascimento']));
		}

		/* PagSeguro objetc to view to get the js address */
		$pagSeguroObject = new PagSeguroData(false, $this->config->get('pagseguro_credit_card_email'), $this->config->get('pagseguro_credit_card_token'));

		$data['pagseguro_js'] = $pagSeguroObject->getJavascriptURL();
		$data['pagseguro_session'] = $this->getSessionId($pagSeguroObject);

		if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/pagseguro_credit_card.tpl')) {
			return $this->load->view($this->config->get('config_template') . '/template/payment/pagseguro_credit_card.tpl', $data);
		} else {
			return $this->load->view('default/template/payment/pagseguro_credit_card.tpl', $data);
		}
	}

	public function payment()
	{
		// Adding parameters
		$pagSeguroObject = new PagSeguroData(false, $this->config->get('pagseguro_credit_card_email'), $this->config->get('pagseguro_credit_card_token'));

		$this->load->model('checkout/order');
		$order_info = $this->model_checkout_order->getOrder((int)$this->session->data['order_id']);
		// $this->log->write(print_r($order_info, true)); exit;

		/* Dados do cliente */

		// obrigatorio nome e sobrenome
		$customer_name = trim(trim($order_info['firstname']) .' '. trim($order_info['lastname']));
		$customer_name = preg_replace('/\s+/', ' ', $customer_name);
		if (strpos($customer_name, ' ') === false) {
			$customer_name .= ' ' . $customer_name;
		}

		$telefone = $this->getDDDNumero($order_info['telephone']);

		$pessoa = isset($order_info['custom_field']['tipo']) ? $order_info['custom_field']['tipo'] : 'f';
		$razao  = isset($order_info['custom_field']['razao']) ? $order_info['custom_field']['razao'] : $customer_name;
		$cpf    = isset($order_info['custom_field']['cpf']) ? $order_info['custom_field']['cpf'] : $this->request->post['creditCardHolderCPF'];
		$cnpj   = isset($order_info['custom_field']['cnpj']) ? $order_info['custom_field']['cnpj'] : '';

		if ($pessoa == 'f') {
			if ($cpf != '') {
				$params['senderCPF'] = preg_replace('/[^0-9]/', '', $cpf);
			}
			$params['senderName'] = $this->mySubstr($customer_name, 0, 50);
		} else {
			if ($cnpj != '') {
				$params['senderCNPJ'] = preg_replace('/[^0-9]/', '', $cnpj);
			}
			$params['senderName'] = $this->mySubstr($razao, 0, 50);
		}
		$params['senderEmail']    = $this->mySubstr(trim($order_info['email']), 0, 60);
		$params['senderAreaCode'] = $telefone[0];
		$params['senderPhone']    = $telefone[1];
		$params['senderHash']     = $this->request->post['senderHash'];

		/* Frete */
		$this->load->model('localisation/zone');

		if ($this->cart->hasShipping()) {
			$shipping_custom_field_numero      = isset($order_info['shipping_custom_field']['numero'])      ? $order_info['shipping_custom_field']['numero']      : '';
			$shipping_custom_field_complemento = isset($order_info['shipping_custom_field']['complemento']) ? $order_info['shipping_custom_field']['complemento'] : '';

			$estado = $this->model_localisation_zone->getZone($order_info['shipping_zone_id']);
			$params['shippingAddressPostalCode'] = $this->mySubstr(preg_replace('/[^0-9]/', '', $order_info['shipping_postcode']), 0, 8);
			$params['shippingAddressStreet']     = $this->mySubstr($order_info['shipping_address_1'], 0, 80);
			$params['shippingAddressNumber']     = $this->mySubstr($shipping_custom_field_numero, 0, 20);
			$params['shippingAddressComplement'] = $this->mySubstr($shipping_custom_field_complemento, 0, 40);
			$params['shippingAddressDistrict']   = $this->mySubstr($order_info['shipping_address_2'], 0, 60);
			$params['shippingAddressCity']       = $this->mySubstr($order_info['shipping_city'], 0, 60);
			$params['shippingAddressState']      = strtoupper($estado['code']);
		} else {
			$payment_custom_field_numero      = isset($order_info['payment_custom_field']['numero'])      ? $order_info['payment_custom_field']['numero']      : '';
			$payment_custom_field_complemento = isset($order_info['payment_custom_field']['complemento']) ? $order_info['payment_custom_field']['complemento'] : '';

			$estado = $this->model_localisation_zone->getZone($order_info['payment_zone_id']);
			$params['shippingAddressPostalCode'] = $this->mySubstr(preg_replace('/[^0-9]/', '', $order_info['payment_postcode']), 0, 8);
			$params['shippingAddressStreet']     = $this->mySubstr($order_info['payment_address_1'], 0, 80);
			$params['shippingAddressNumber']     = $this->mySubstr($payment_custom_field_numero, 0, 20);
			$params['shippingAddressComplement'] = $this->mySubstr($payment_custom_field_complemento, 0, 40);
			$params['shippingAddressDistrict']   = $this->mySubstr($order_info['payment_address_2'], 0, 60);
			$params['shippingAddressCity']       = $this->mySubstr($order_info['payment_city'], 0, 60);
			$params['shippingAddressState']      = strtoupper($estado['code']);
		}

		if ($params['shippingAddressNumber'] == '' || $params['shippingAddressNumber'] == false) {
			$params['shippingAddressNumber'] = 's/n';
		}
		if ($params['shippingAddressDistrict'] == '' || $params['shippingAddressDistrict'] == false) {
			$params['shippingAddressDistrict'] = 'sem bairro';
		}

		$params['shippingAddressCountry'] = 'BRA';
		$params['shippingType'] = 3; // 1=pac; 2=sedex; 3=não especificado;

		/* Produtos */

		$i = 1;

		foreach ($this->cart->getProducts() as $product) {
			if ($product['price'] <= 0) { continue; }

			$options_names = array();
			foreach ($product['option'] as $option) {
				if (in_array($option['type'], array('select','radio','checkbox','image'))) {
					$options_names[] = $option['value'];
				}
			}
			$options_names = implode('/', $options_names);
			if ($options_names) { $options_names = " ({$options_names})"; }

			$params['itemId' . $i]          = $product['product_id'];
			$params['itemDescription' . $i] = $this->mySubstr($product['name'] . $options_names, 0, 90);
			$params['itemAmount' . $i]      = $this->currency->format($product['price'], $order_info['currency_code'], false, false);
			$params['itemQuantity' . $i]    = $product['quantity'];

			$i++;
		}

		/* Dados do cartão */
		$params['creditCardToken']      = $this->request->post['creditCardToken'];
		$params['installmentQuantity']  = $this->request->post['installmentQuantity'];
		$params['installmentValue']     = $this->currency->format($this->request->post['installmentValue'], $order_info['currency_code'], false, false);

		// if ($params['installmentQuantity'] == 1) {
		// 	$params['installmentValue'] = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false);
		// }

		/* Endereço de cobrança */
		$estado = $this->model_localisation_zone->getZone($this->request->post['shippingAddressState']);
		$params['billingAddressPostalCode'] = $this->mySubstr(preg_replace('/[^0-9]/', '', $this->request->post['shippingAddressPostalCode']), 0, 8);
		$params['billingAddressStreet']     = $this->mySubstr($this->request->post['shippingAddressStreet'], 0, 80);
		$params['billingAddressNumber']     = $this->mySubstr($this->request->post['shippingAddressNumber'], 0, 20);
		$params['billingAddressComplement'] = $this->mySubstr($this->request->post['shippingAddressComplement'], 0, 40);
		$params['billingAddressDistrict']   = $this->mySubstr($this->request->post['shippingAddressDistrict'], 0, 60);
		$params['billingAddressCity']       = $this->mySubstr($this->request->post['shippingAddressCity'], 0, 60);
		$params['billingAddressState']      = strtoupper($estado['code']);
		$params['billingAddressCountry']    = 'BRA';

		if ($params['billingAddressDistrict'] == '' || $params['billingAddressDistrict'] == false) {
			$params['billingAddressDistrict'] = 'sem bairro';
		}

		$telefone2 = $this->getDDDNumero($this->request->post['creditCardHolderPhone']);
		$params['creditCardHolderCPF']       = preg_replace('/[^0-9]/', '', $this->request->post['creditCardHolderCPF']);
		$params['creditCardHolderName']      = $this->mySubstr($this->request->post['creditCardHolderName'], 0, 50);
		$params['creditCardHolderBirthDate'] = $this->request->post['creditCardHolderBirthDate'];
		$params['creditCardHolderAreaCode']  = $telefone2[0];
		$params['creditCardHolderPhone']     = $telefone2[1];

		// url para receber notificações sobre o status das transações
		$params['notificationURL'] = $this->url->link('payment/pagseguro_credit_card/callback');

		// obtendo frete, descontos e taxas
		$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false);
		$params['extraAmount'] = $total;

		$params['paymentMethod'] = 'creditCard';
		$params['paymentMode']   = 'default'; // paymentMode
		$params['currency']      = 'BRL'; // Currency (only BRL)
		$params['reference']     = $order_info['order_id']; // Setting the Application Order to Reference on PagSeguro

		$params += $pagSeguroObject->getCredentials(); // add credentials
		// $this->response->setOutput(json_encode($params)); exit;

		// treat parameters here!
		$httpConnection = new PagSeguroHttpConnection();
		$httpConnection->post($pagSeguroObject->getTransactionsURL(), $params);

		// Get Xml From response body
		$xmlArray = $this->paymentResultXml($httpConnection->getResponse());

		$json = array();

		if (array_key_exists('errors', $xmlArray)) {
			foreach ($xmlArray['errors'] as $error) {
				$this->log->write('Erro PagSeguro CC: ' . print_r($error, true));
			}
			$json['error'] = true;
		} else {
			$json['success'] = true;
		}

		$this->response->addHeader('Content-Type: application/json');
		$this->response->setOutput(json_encode($json));
	}

	public function confirm()
	{
		$this->load->model('checkout/order');

		$this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('pagseguro_credit_card_order_aguardando_pagamento'), '', true);

		$this->response->redirect($this->url->link('checkout/success'));
	}

	public function callback()
	{
		$code = isset($_REQUEST['notificationCode']) && trim($_REQUEST['notificationCode']) !== '' ? trim($_REQUEST['notificationCode']) : null;
		$type = isset($_REQUEST['notificationType']) && trim($_REQUEST['notificationType']) !== '' ? trim($_REQUEST['notificationType']) : null;
		// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC Log 1', 'Post: '.print_r($_REQUEST,true)."\n\n".date('Y-m-d H:i:s'));
		// $this->log->write('PagSeguro CC: Log 1: Post: '.print_r($_REQUEST,true));

		if ($code && $type) {
			$notificationType = new PagSeguroNotificationType($type);
			$strType = $notificationType->getTypeFromValue();

			if ($strType == 'TRANSACTION') {
				try {
					$credentials = new PagSeguroAccountCredentials($this->config->get('pagseguro_credit_card_email'), $this->config->get('pagseguro_credit_card_token'));
					$transaction = PagSeguroNotificationService::checkTransaction($credentials, $code);
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC Log 2', "transaction: ".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					// $this->log->write('PagSeguro CC: Log 2: transaction: '.print_r($transaction,true));

					$status = $transaction->getStatus()->getTypeFromValue();
					$reference = $transaction->getReference();
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC Log 3', "transactionStatus: {$status}\nid_pedido: {$reference}\n\n".date('Y-m-d H:i:s'));
					// $this->log->write("PagSeguro CC: Log 3: transactionStatus: {$status} / id_pedido: {$reference}");

					$order_id = explode('_', preg_replace('/_+/', '_', $reference));
					$order_id = $order_id[0];

					$this->load->model('checkout/order');
					$order = $this->model_checkout_order->getOrder($order_id);
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC Log 4', "order: ".print_r($order,true)."\n\n".date('Y-m-d H:i:s'));
					// $this->log->write('PagSeguro CC: Log 4: order: '.print_r($order,true));

					$update_status_alert = false;
					if ($this->config->get('pagseguro_credit_card_update_status_alert') == '1') {
						$update_status_alert = true;
					}

					if ($order['order_status_id'] == '0') {
						$this->model_checkout_order->addOrderHistory($order_id, $this->config->get('pagseguro_credit_card_order_aguardando_pagamento'), '', true);
					}

					switch($status){

					// 'WAITING_PAYMENT' => 1
					case 'WAITING_PAYMENT':
						$order_aguardando_pagamento = $this->config->get('pagseguro_credit_card_order_aguardando_pagamento');
						if (is_numeric($order_aguardando_pagamento) && $order_aguardando_pagamento > 0) {
							if ($order['order_status_id'] != $order_aguardando_pagamento) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_aguardando_pagamento, '', $update_status_alert);
							}
						}
						break;

					// 'IN_ANALYSIS' => 2
					case 'IN_ANALYSIS':
						$order_analise = $this->config->get('pagseguro_credit_card_order_analise');
						if (is_numeric($order_analise) && $order_analise > 0) {
							if ($order['order_status_id'] != $order_analise) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_analise, '', $update_status_alert);
							}
						}
						break;

					// 'PAID' => 3
					case 'PAID':
						$order_paga = $this->config->get('pagseguro_credit_card_order_paga');
						if (is_numeric($order_paga) && $order_paga > 0) {
							if ($order['order_status_id'] != $order_paga) {
								// $paymentMethod = $transaction->getPaymentMethod();
								// $paymentCode   = $paymentMethod->getCode()->getTypeFromValue();
								// $pagamento    = $paymentCode->getTypeFromValue();

								$pagamento = $transaction->getPaymentMethod()->getCode()->getTypeFromValue();
								$parcelas  = $transaction->getInstallmentCount();

								// Obtendo o tipo de pagamento escolhido
								$comment = "Tipo de pagamento escolhido: {$pagamento} / Número de parcelas: {$parcelas}";
								// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC Log 5', "comment: {$comment}\n\n".date('Y-m-d H:i:s'));
								// $this->log->write("PagSeguro CC: Log 5: comment: {$comment}");

								$this->model_checkout_order->addOrderHistory($order_id, $order_paga, $comment, $update_status_alert);
							}
						}
						break;

					// 'AVAILABLE' => 4
					case 'AVAILABLE':
						$order_disponivel = $this->config->get('pagseguro_credit_card_order_disponivel');
						if (is_numeric($order_disponivel) && $order_disponivel > 0) {
							if ($order['order_status_id'] != $order_disponivel) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_disponivel, '', $update_status_alert);
							}
						}
						break;

					// 'IN_DISPUTE' => 5
					case 'IN_DISPUTE':
						$order_disputa = $this->config->get('pagseguro_credit_card_order_disputa');
						if (is_numeric($order_disputa) && $order_disputa > 0) {
							if ($order['order_status_id'] != $order_disputa) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_disputa, '', $update_status_alert);
							}
						}
						break;

					// 'REFUNDED' => 6
					case 'REFUNDED':
						$order_devolvida = $this->config->get('pagseguro_credit_card_order_devolvida');
						if (is_numeric($order_devolvida) && $order_devolvida > 0) {
							if ($order['order_status_id'] != $order_devolvida) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_devolvida, '', $update_status_alert);
							}
						}
						break;

					// 'CANCELLED' => 7
					case 'CANCELLED':
						$order_cancelada = $this->config->get('pagseguro_credit_card_order_cancelada');
						if (is_numeric($order_cancelada) && $order_cancelada > 0) {
							if ($order['order_status_id'] != $order_cancelada) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_cancelada, '', $update_status_alert);
							}
						}
						break;

					// 'SELLER_CHARGEBACK' => 8
					case 'SELLER_CHARGEBACK':
						$order_chargeback = $this->config->get('pagseguro_credit_card_order_chargeback');
						if (is_numeric($order_chargeback) && $order_chargeback > 0) {
							if ($order['order_status_id'] != $order_chargeback) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_chargeback, '', $update_status_alert);
							}
						}
						break;

					// 'CONTESTATION' => 9
					case 'CONTESTATION':
						$order_contestacao = $this->config->get('pagseguro_credit_card_order_contestacao');
						if (is_numeric($order_contestacao) && $order_contestacao > 0) {
							if ($order['order_status_id'] != $order_contestacao) {
								$this->model_checkout_order->addOrderHistory($order_id, $order_contestacao, '', $update_status_alert);
							}
						}
						break;
					}

				} catch (PagSeguroServiceException $e) {
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC', "Erro 1: ".$e->getMessage()."\n\n".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					$this->log->write('PagSeguro CC: Erro 1: '.$e->getMessage()."\n\n".print_r($transaction,true));
				} catch (Exception $e) {
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro CC', "Erro 2: ".$e->getMessage()."\n\n".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					$this->log->write('PagSeguro CC: Erro 2: '.$e->getMessage()."\n\n".print_r($transaction,true));
				}

			} else {
				$this->log->write("PagSeguro CC: tipo de notificação desconhecido [{$type}]");
			}

		} else {
			$this->log->write('PagSeguro CC: Parâmetros de notificação inválidos. Request: '.print_r($_REQUEST,true));
		}
	}

	private function getSessionId(PagSeguroData $pagSeguroData)
	{
		// Creating a http connection (CURL abstraction)
		$httpConnection = new PagSeguroHttpConnection();

		// Request to PagSeguro Session API using Credentials
		$httpConnection->post($pagSeguroData->getSessionURL(), $pagSeguroData->getCredentials());

		// Request OK getting the result
		if ($httpConnection->getStatus() === 200) {
			$data = $httpConnection->getResponse();

			$sessionId = $this->parseSessionIdFromXml($data);

			return $sessionId;
		} else {
			throw new Exception("PagSeguro CC: API Request Error: " . $httpConnection->getStatus());
		}
	}

	private function parseSessionIdFromXml($data)
	{
		// Creating an xml parser
		$xmlParser = new PagSeguroXmlParser($data);

		// Verifying if is an XML
		if ($xml = $xmlParser->getResult("session")) {
			// Retrieving the id from "session node"
			return $xml['id'];
		} else {
			throw new Exception("PagSeguro CC: [{$data}] is not an XML");
		}
	}

	private function getDDDNumero($telefone)
	{
		$telefone = str_replace(array('(', ')', '-', '.', '/'), '', $telefone);
		$telefone = explode(' ', $telefone);
		return $telefone;
	}

	private function mySubstr($string, $start = 0, $limit = 10)
	{
		if (function_exists("mb_substr")) {
			$string = mb_substr($string, $start, $limit, 'UTF-8');
		} else {
			$string = utf8_encode(substr(utf8_decode($string), $start, $limit));
		}

		return $string;
	}

	private function paymentResultXml($data)
	{
		// Creating an xml parser
		$xmlParser = new PagSeguroXmlParser($data);

		// Verifying if is an XML
		if ($xml = $xmlParser->getResult()) {
			return $xml;
		} else {
			throw new Exception("PagSeguro CC: [{$data}] is not an XML");
		}
	}

}
