<?php

namespace Icetech\Payment\Gateway;


use GuzzleHttp\Client;

/**
 * Banca Transilvania Payment Gateway.
 *
 * (c) Draga Sergiu 05/2019
 * (c) Icetech 2018
 *
 */
class Bt extends PaymentGateway
{

    protected $status = [
        'confirmed_pending' => self::STATUS_PENDING, // transaction is pending review. After this is done, a new IPN request will be sent with either confirmation or cancellation
        'paid_pending' => self::STATUS_PENDING, // transaction is pending review. After this is done, a new IPN request will be sent with either confirmation or cancellation
        'paid' => self::STATUS_PREAUTHORIZED, // transaction is pending authorization. After this is done, a new IPN request will be sent with either confirmation or cancellation
        'bla' => self::STATUS_REFUNDED, // transaction has been refunded

//        0 => self::STATUS_PAID, // transaction is finalized, the money have been captured from the customer's account
        0 => self::STATUS_PREAUTHORIZED, // transaction is pending authorization. After this is done, a new IPN request will be sent with either confirmation or cancellation

        2 => self::STATUS_CANCELED, // transaction is canceled
        320 => self::STATUS_CANCELED,
        801 => self::STATUS_CANCELED,
        803 => self::STATUS_CANCELED,
        805 => self::STATUS_CANCELED,
        861 => self::STATUS_CANCELED,
        871 => self::STATUS_CANCELED,
        906 => self::STATUS_CANCELED,
        914 => self::STATUS_CANCELED,
        915 => self::STATUS_CANCELED,
        917 => self::STATUS_CANCELED,
        -2006 => self::STATUS_CANCELED,
    ];

    protected $errors = [
        0 => 'success',
        320 => 'Card inactiv. Va rugam activati cardul',
        801 => 'Emitent indisponibil',
        803 => 'Card blocat. Va rugam contactati banca emitenta.',
        805 => 'Tranzactie respinsa',
        861 => 'Data expirare card gresita',
        871 => 'CVV gresit',
        906 => 'Card expirat',
        914 => 'Cont invalid. Va rugam contactati banca emitenta.',
        915 => 'Fonduri insuficiente.',
        917 => 'Limita tranzactionare depasita.',
        -2006 => 'Autorizare esuata',
    ];

    public function __construct()
    {
        parent::__construct();
    }

    public function getContactKeyMappings()
    {
        return [
            'firstName' => 'firstname',
            'lastName' => 'lastname',
            'address' => 'address',
            'email' => 'email',
            'mobilePhone' => 'phone',
            'country' => ['country', 'name'],
            'county' => ['county', 'name'],
            'city' => 'city',
            'zipCode' => 'postalcode',
        ];
    }

    public function getOrderIdParamName()
    {
        return 'orderId';
    }

    /**
     * BT ask the amounts as cents.
     *
     * @param $value
     * @return PaymentGateway
     */
    public function setAmount($value)
    {
        return parent::setAmount($value * 100);
    }


    /**
     * BT uses a simple REST API.
     *
     * @param $endpoint
     * @param array $paramsb
     * @return \Psr\Http\Message\StreamInterface
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function connect($endpoint, array $params)
    {
        $client = new Client([
            'verify' => false
        ]);


        $response = $client->request('POST', $this->endpoint_url . $endpoint . '.do', [
            'form_params' => [
                    'userName' => $this->username,
                    'password' => $this->password,
                    'language' => $this->language,
//                'orderId' => $this->getOrderId(),
                ] + $params,
        ]);

        return json_decode($response->getBody()->getContents());
    }

    public function oneStepPayment()
    {
        return $this->connect('register', [
            'amount' => $this->getAmount(),
            'orderNumber' => $this->getOrderId(),
            'returnUrl' => $this->confirm_url, // in case of BT, the return is a confirm!
            'failUrl' => $this->confirm_url,
            'installment' => $this->installment ? $this->installment_period : null,
            'description' => 'Plata comanda ' . $this->getOrderId() . ' ' . config('app.name'),
        ]);


        if (empty($response->formUrl)) {
            dd('Erorare', $response);
        }

    }

    public function generatePurchaseParams()
    {
        $order = $this->order;

        $response = $this->connect('registerPreAuth', [
            'amount' => $this->getAmount(),
            'orderNumber' => $this->getOrderId(),
            'returnUrl' => $this->confirm_url,
            'failUrl' => $this->confirm_url,
            'installment' => $this->installment ? $this->installment_period : null,
//            'installment' => 6,
            'description' => 'Plata comanda ' . $this->getOrderId() . ' ' . config('app.name'),
            'jsonParams' => json_encode([
                'FORCE_3DS2' => 'true',
            ]),
            'orderBundle' => json_encode([
                'orderCreationDate' => $order->created_at->format('Y-m-d'),
                'customerDetails' => [
                    'email' => $order->deliveryContact->email ?? config('mail.office.address'),
                    // Trebuie să contină doar cifre, în format internațional (de ex. 40740123456).
                    // (obligatoriu cu cifra 4 in fata pentru numere de Romania)
                    'phone' => $this->formatPhone($order->deliveryContact->phone),
                    'contact' => $order->deliveryContact->getName(),
                    'deliveryInfo' => [
                        // online | comanda
                        'deliveryType' => 'comanda',
                        // Țara de livrare / facturare, conform ISO 3166-1
                        'country' => 642,
                        'city' => substr($order->deliveryContact->city ?? '', 0, 50),
                        'postAddress' => substr($order->deliveryContact->address ?? '', 0, 50),
                        'postalCode' => substr($order->deliveryContact->postalcode ?? '', 0, 15),
                    ],
                    'billingInfo' => [
                        // online | comanda
                        'deliveryType' => 'comanda',
                        // Țara de livrare / facturare, conform ISO 3166-1
                        'country' => 642,
                        'city' => substr($order->billingContact->city ?? '', 0, 50),
                        'postAddress' => substr($order->billingContact->address ?? '', 0, 50),
                        'postalCode' => substr($order->billingContact->postalcode ?? '', 0, 15),
                    ]
                ]
            ])
        ]);


        if (empty($response->formUrl)) {
            dd('Erorare', $response);
        }

        // @todo addd costumer data vor invoice?

        return [
            'directUrl' => $response->formUrl,
        ];

    }

    public function response()
    {

        // if using getOrderStatusExtended, the eroror is present in actionCode, othweise getOrderStatus in ErrorCode
        $response = $this->connect('getOrderStatusExtended', [
            'orderId' => request($this->getOrderIdParamName()),
        ]);

        if (empty($response->orderNumber)) {
            dd($response);
        }

        // 1. set orderId
        $this->setOrderId($response->orderNumber);


        // 2. set responseData.
        $this->setResponseData([
            'error_code' => $response->actionCode,
            'error_message' => $this->errors[$response->actionCode] ?? $response->actionCodeDescription,
            'action' => $response->actionCode,
            'external_order_id' => $response->attributes[0]->value ?? null,
            'raw' => $response,
        ]);

        return $this;
    }

    public function callbackOutput($track_conversion = false)
    {
        return redirect($this->return_url . '?' . http_build_query([$this->getOrderIdParamName() => $this->getOrderId(), 'good' => $track_conversion]));
    }


    public function deposit()
    {
        $response = $this->connect('deposit', [
            'amount' => $this->getAmount(),
            'orderId' => $this->getOrderId(),
        ]);

        return (object)[
            'raw' => $response,
            'status' => $response->errorCode == 0,
            'code' => $response->errorCode,
        ];
    }

    public function reverse()
    {
        $response = $this->connect('reverse', [
            'amount' => $this->getAmount(),
            'orderId' => $this->getOrderId(),
        ]);

        return (object)[
            'raw' => $response,
            'status' => $response->errorCode == 0,
            'code' => $response->errorCode,
        ];
    }

    /*
     Possible formats:

     0722209371 sau 0768838817
    +40740000000
    40740000000,40740000000,40740000000
    40740000000, 40740000000
    40740000000 / 40740000000
     */
    public function formatPhone($phone)
    {
        // break phone text (it may contain multiple phones)
        preg_match_all('#(?<phone>[\d\+\s\(\)]+)#', $phone, $parts);
        // remove everything but digits from first detected phone number
        $phone = preg_replace('#[^\d]+#', '', $parts['phone'][0] ?? $phone);
        // remove the leading 0040
        $phone = preg_replace('#^0040#', '', $phone);
        // remove the leading 0
        $phone = preg_replace('#^0#', '', $phone);
        // daca nu aveti numar de telefon, completati la phone “40740000000”
        // acesta trebuie sa contina doar cifre in format international si sa fie de maxim 15 cifre
        // (obligatoriu cu cifra 4 in fata pentru numere de Romania)
        if (!$phone) {
            return '40740000000';
        }
        if (substr($phone, 0, 2) != '40') {
            $phone = '40' . $phone;
        }
        // maximum of 15 chars.
        return substr($phone, 0, 15);
    }

}
