<?php

require_once DIR_SYSTEM . 'library/PagSeguroLibrary/PagSeguroLibrary.php';

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

		$data['button_confirm'] = $this->language->get('button_confirm_pagseguro');
		$data['text_instruction'] = $this->language->get('text_instruction');
		$data['text_loading'] = $this->language->get('text_loading');

		$order_id = (int)$this->session->data['order_id'];

		$this->load->model('checkout/order');
		$order_info = $this->model_checkout_order->getOrder($order_id);

		$language_id = $this->config->get('config_language_id');

		$paymentRequest = new PagSeguroPaymentRequest();
		$paymentRequest->setCurrency($order_info['currency_code']);

		/*
		 * Dados do cliente
		 */

		$customer_name = trim($order_info['payment_firstname'] .' '. $order_info['payment_lastname']);

		// ajuste no nome do comprador para o maximo de 50 caracteres exigido pela API
		$customer_name = mb_substr($customer_name, 0, 50);

		if(strlen($customer_name) > 3 && strpos($customer_name,' ') !== FALSE){
			// a API exige que o nome seja composto de pelo menos 2 palavras, ou seja, deve conter pelo menos um espaco
			$paymentRequest->setSenderName($customer_name);
		}

		$customer_email = trim($order_info['email']);

		if(strlen($customer_email) <= 60){
			// limitacao de 60 caracteres de acordo com a API
			$paymentRequest->setSenderEmail($customer_email);
		}

		$customer_telephone = preg_replace("/[^0-9]/", '', $order_info['telephone']);

		if(strlen($customer_telephone) == 10 || strlen($customer_telephone) == 11){
			// OpenCart nao separa o DDD do numero do telefone. Assim, tentamos separa-los, mas somente se o telefone obedecer ao padrao de 10 ou 11 digitos
			$paymentRequest->setSenderPhone(substr($customer_telephone, 0, 2), substr($customer_telephone, 2));
		}

		$customer_cpf = isset($order_info['custom_field']['cpf']) ? $order_info['custom_field']['cpf'] : '';

		if($this->validaCPF($customer_cpf)){
			$paymentRequest->addSenderDocument('CPF', $customer_cpf);
		}

		/*
		 * Frete
		 */

		$paymentRequest->setShippingType(3); // 1=pac; 2=sedex; 3=não especificado;

		$field = $this->cart->hasShipping() ? 'shipping' : 'payment';

		$this->load->model('localisation/zone');
		$zone = $this->model_localisation_zone->getZone($order_info["{$field}_zone_id"]);

		$customer_postalcode = preg_replace ('/[^0-9]/', '', $order_info["{$field}_postcode"]);
		$customer_street     = $order_info["{$field}_address_1"];
		$customer_number     = isset($order_info["{$field}_custom_field"]['numero']) ? $order_info["{$field}_custom_field"]['numero'] : '';
		$customer_complement = isset($order_info["{$field}_custom_field"]['complemento']) ? $order_info["{$field}_custom_field"]['complemento'] : '';
		$customer_district   = $order_info["{$field}_address_2"];
		$customer_city       = $order_info["{$field}_city"];
		$customer_state      = isset($zone['code']) ? $zone['code'] : '';
		$customer_country    = $order_info["{$field}_iso_code_3"];

		// Endereco para entrega
		$paymentRequest->setShippingAddress(
			$customer_postalcode,
			$customer_street,
			$customer_number,
			$customer_complement,
			$customer_district,
			$customer_city,
			$customer_state,
			$customer_country
		);

		/*
		 * Produtos
		 */

		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})"; }

			// limite de 100 caracteres para a descricao do produto
			$description = mb_substr($product['name'].$options_names, 0, 90, 'UTF-8');

			$item = array(
				'id'          => $product['product_id'],
				'description' => $description,
				'quantity'    => $product['quantity'],
				'amount'      => $this->currency->convert($product['price'], $this->config->get('config_currency'), $order_info['currency_code'])
			);

			$paymentRequest->addItem($item);
		}

		// vales presentes
		$vouchers = isset($this->session->data['vouchers']) ? $this->session->data['vouchers'] : array();

		$total_voucher = 0;
		$count_voucher = 0;

		foreach ($vouchers as $voucher_id => $voucher) {
			$count_voucher++;

			$amount = $this->currency->convert($voucher['amount'], $this->config->get('config_currency'), $order_info['currency_code']);

			$item = array(
				'id'           => 'voucher_'.$count_voucher,
				'description'  => mb_substr($voucher['description'], 0, 100, 'UTF-8'),
				'quantity'     => 1,
				'amount'       => $amount,
				'weight'       => 0,
				'shippingCost' => 0
			);

			$paymentRequest->addItem($item);

			$total_voucher += $amount;
		}

		// total extra do pedido (frete, descontos e taxas) pode ser um valor positivo ou negativo
		$total_extra = $this->currency->format($order_info['total'] - $this->cart->getSubTotal() - $total_voucher, $order_info['currency_code'], false, false);

		// se o extra for positivo adiciona como produto
		if ($total_extra > 0) {
			$item = array(
				'id'           => 'extra_amount',
				'description'  => mb_substr($this->language->get('text_extra_amount'), 0, 100, 'UTF-8'),
				'quantity'     => 1,
				'amount'       => $total_extra,
				'weight'       => 0,
				'shippingCost' => 0
			);

			$paymentRequest->addItem($item);
		}
		// se o extra for negativo envia como desconto
		elseif ($total_extra < 0) {
			$paymentRequest->setExtraAmount($total_extra);
		}


		// referencia do pedido
		if ($this->config->get('pagseguro_posfixo') != '') {
			$paymentRequest->setReference($order_id . '_' . $this->config->get('pagseguro_posfixo'));
		} else {
			$paymentRequest->setReference($order_id);
		}

		// url para redirecionar o comprador ao finalizar o pagamento
		$paymentRequest->setRedirectUrl($this->url->link('checkout/success'));

		// url para notificacao automatica de mudancas de status
		$paymentRequest->setNotificationURL($this->url->link('payment/pagseguro/callback'));

		/*echo("Weight: "); print_r($this->cart->getWeight()); echo("\n\n");
		echo("SubTotal: "); print_r($this->cart->getSubTotal()); echo("\n\n");
		echo("Total: "); print_r($this->cart->getTotal()); echo("\n\n");
		echo("Taxes: "); print_r($this->cart->getTaxes()); echo("\n\n");
		exit;*/

		/*
		 * Fazendo a chamada para a API de Pagamentos do PagSeguro.
		 * Se tiver sucesso, retorna o codigo (url) de requisicao para este pagamento.
		 */
		try {
			$credentials = new PagSeguroAccountCredentials($this->config->get('pagseguro_email'), $this->config->get('pagseguro_token'));
			$url = $paymentRequest->register($credentials);
			$data['continue'] = $url;

		} catch (PagSeguroServiceException $e) {
			$this->log->write('PagSeguro: '.$e->getMessage());
			die($e->getMessage());
		} catch (Exception $e) {
			$this->log->write('PagSeguro: '.$e->getMessage());
			die($e->getMessage());
		}

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

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

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

	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 Log 1', 'Post: '.print_r($_REQUEST,true)."\n\n".date('Y-m-d H:i:s'));
		// $this->log->write('PagSeguro: 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_email'), $this->config->get('pagseguro_token'));
					$transaction = PagSeguroNotificationService::checkTransaction($credentials, $code);
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro Log 2', "transaction: ".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					// $this->log->write('PagSeguro: Log 2: transaction: '.print_r($transaction,true));

					$status = $transaction->getStatus()->getTypeFromValue();
					$reference = $transaction->getReference();
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro Log 3', "transactionStatus: {$status}\nid_pedido: {$reference}\n\n".date('Y-m-d H:i:s'));
					// $this->log->write("PagSeguro: 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 Log 4', "order: ".print_r($order,true)."\n\n".date('Y-m-d H:i:s'));
					// $this->log->write('PagSeguro: Log 4: order: '.print_r($order,true));

					$update_status_alert = false;
					if ($this->config->get('pagseguro_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_order_aguardando_retorno'), '', true);
					}

					switch($status){

					// 'WAITING_PAYMENT' => 1
					case 'WAITING_PAYMENT':
						$order_aguardando_pagamento = $this->config->get('pagseguro_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_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_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 Log 5', "comment: {$comment}\n\n".date('Y-m-d H:i:s'));
								// $this->log->write("PagSeguro: 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_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_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_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_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_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_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', "Erro 1: ".$e->getMessage()."\n\n".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					$this->log->write('PagSeguro: Erro 1: '.$e->getMessage()."\n\n".print_r($transaction,true));
				} catch (Exception $e) {
					// @mail('eric@hoteldaweb.com.br', 'PagSeguro', "Erro 2: ".$e->getMessage()."\n\n".print_r($transaction,true)."\n\n".date('Y-m-d H:i:s'));
					$this->log->write('PagSeguro: Erro 2: '.$e->getMessage()."\n\n".print_r($transaction,true));
				}

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

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

	private function validaCPF($strCPF){
		// validacao: apenas numeros ou no formato 000.000.000-00
		if (!preg_match('/^[0-9]{11}$/', $strCPF) && !preg_match('/^[0-9]{3}\.[0-9]{3}\.[0-9]{3}-[0-9]{2}$/', $strCPF)) { return false; }

		// remove caracteres nao numericos (pontuacao)
		$strCPF = preg_replace('/[^0-9]/', '', $strCPF);

		// nao aceita sequencias de numeros iguais (00000000000, 11111111111, etc)
		for ($a = 0; $a < 10; $a++) {
			if (str_repeat($a, 11) == $strCPF) { return false; }
		}

		// digito verificador informado
		$strCPF_dv = substr($strCPF, 9, 2);

		// separa os digitos
		$digito = str_split($strCPF);

		// calcula o digito verificador
		$mult = 10; $soma = 0;
		for ($a = 0; $a < 9; $a++) { $soma += $digito[$a] * $mult--; }
		$soma = $soma % 11;
		$digito[9] = ($soma < 2) ? 0 : 11 - $soma;

		$mult = 11; $soma = 0;
		for ($a = 0; $a < 10; $a++){ $soma += $digito[$a] * $mult--; }
		$soma = $soma % 11;
		$digito[10] = ($soma < 2) ? 0 : 11 - $soma;

		// verifica se o digito verificador informado e igual ao calculado
		$digitoVerificador = $digito[9] .''. $digito[10];
		if ($digitoVerificador != $strCPF_dv) { return false; }

		return true;
	}
}