<?php

use Diglin\Intrum\CreditDecision\Request;
use Diglin\Intrum\CreditDecision\Response;
use Diglin\Intrum\CreditDecision\TransportV0017;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Util\Compat\SymfonyBridge;

class Intrum extends Payment
{
    public static $name = 'Intrum';

    public $template = 'payment.Intrum.tpl';

    public $class = self::class;

    protected $pay_method = Payment::METHOD_INVOICE;

    public static $REQUEST_ENQUIRY_CREDIT_ASSESSMENT = 0;
    public static $REQUEST_ENQUIRY_BUSINESS_TRANSACTION = 1;
    public static $REQUEST_SEND_PAYMENT_TRANSACTION_RECEIPT = 3;
    public static $REQUEST_SEND_PAYMENT_TRANSACTION_CANCEL = 6;

    public $states = [
        1 => 'There are serious negative indicators',
        2 => 'All payment methods',
        3 => 'Manual post-processing (currently not yet in use)',
        4 => 'Postal address is incorrect',
        5 => 'Enquiry exceeds the credit limit (the credit limit is specified in the cooperation agreement)',
        6 => 'Customer specifications not met (currently not yet in use)',
        7 => 'Enquiry exceeds the net credit limit (enquiry amount plus open items exceeds credit limit)',
        8 => 'Person queried is not of creditworthy age',
        9 => 'Delivery address does not match invoice address (for payment guarantee only)',
        10 => 'Household cannot be identified at this address',
        11 => 'Country is not supported',
        12 => 'Party queried is not a natural person',
        13 => 'System is in maintenance mode',
        14 => 'Address with high fraud risk',
        15 => 'Allowance is too low',
        16 => 'Application data incomplete',
        17 => 'Send contract documents for external credit check',
        18 => 'External credit check in progress',
        19 => 'Customer is on client blacklist',
        20 => 'Customer is on client whitelist',
        21 => 'Customer is on Intrum blacklist',
        22 => 'Address is a P.O. box',
        23 => 'Address not in residential area',
        24 => 'Ordering person not legitimated',
        25 => 'IP Address temporarily blacklisted',
        50 => 'Blacklist WSNP (NL only)',
        51 => 'Blacklist Bankruptcy (NL only)',
        52 => 'Blacklist Fraud (NL only)',
    ];

    /**
     * @throws Exception
     */
    public function check(CartBase $cart)
    {
        // skip if not last step
        $step = end($cart->steps);
        if (!($step ?? false) || !($step['selected'] ?? false)) {
            return;
        }

        if (empty($cart->invoice['birthdate'])
            || DateTime::createFromFormat('d-m-Y', $cart->invoice['birthdate']) === false
        ) {
            addUserMessage(replacePlaceholders(translate('checkDataOrChangeDelivery', 'payment'), ['URL' => '/'.$cart->steps['user']['url']]), 'danger');
            redirection($cart->steps['delivery']['url']);
        }

        $hash = $this->createHash(array_merge($cart->invoice, [$cart->totalPricePay->printValue()]));
        $oldHash = $cart->getData($this->class.'_hash');
        $counter = $cart->getData($this->class.'_counter');
        try {
            if (isset($oldHash) && $oldHash === $hash) {
                $requestID = $cart->getData($this->class.'_enquiryCreditRequest');
                $requestResponse = $this->selectSQL('intrum_requests', ['id' => $requestID])->fetch()['response'];
                if ($requestResponse) {
                    $this->checkRawResponse($requestResponse, $requestID);
                } else {
                    $cart->setData($this->class.'_hash', null);
                    $cart->setData($this->class.'_enquiryCreditRequest', null);
                    $cart->setData($this->class.'_counter', null);
                    $cart->setData($this->class.'_counter', 1);
                    $this->enquiryCreditAssessment($cart, $hash);
                }

                return;
            }

            if (!isset($counter) || $counter <= 2) {
                $cart->setData($this->class.'_counter', ($counter ?? 0) + 1);
                $this->enquiryCreditAssessment($cart, $hash);
            } else {
                addUserMessage(mb_ucfirst(translate('changePaymentMethod', 'payment')), 'danger');
                redirection($cart->steps['delivery']['url']);
            }
        } catch (RuntimeException $e) {
            addUserMessage(replacePlaceholders(translate('checkDataOrChangeDelivery', 'payment'), ['URL' => '/'.$cart->steps['user']['url']]), 'danger');
            redirection($cart->steps['delivery']['url']);
        }
    }

    /**
     * @return bool TRUE if response status is 2 (All payment methods)
     *
     * @throws Exception
     */
    private function checkRawResponse(string $rawResponse, int $requestID): bool
    {
        $response = new Response();
        $response->setRawResponse($rawResponse);
        $response->processResponse();
        if ($response->getCustomerRequestStatus() !== 2) {
            throw new RuntimeException($this->states[$response->getCustomerRequestStatus()] ?? 'Unknown Intrum error in request '.$requestID.'.');
        }

        return true;
    }

    /**
     * @throws Exception
     */
    private function enquiryCreditAssessment(CartBase $cart, string $hash)
    {
        $streetArray = explode(' ', $cart->invoice['street']);
        $houseNumber = count($streetArray) > 1 ? array_pop($streetArray) : ' ';
        $firstLine = join(' ', $streetArray);
        $birthdate = DateTime::createFromFormat('d-m-Y', $cart->invoice['birthdate'])->format('Y-m-d');
        $data = [
            'customer_reference' => 'uid_'.uniqid(),
            'person' => [
                'first_name' => $cart->invoice['name'],
                'last_name' => $cart->invoice['surname'],
                'gender' => $cart->invoice['gender'] === 'female' ? 2 : 1,
                'date_of_birth' => $birthdate, // YYYY-MM-DD
                'current_address' => [
                    'first_line' => $firstLine,
                    'house_number' => $houseNumber,
                    'post_code' => $cart->invoice['zip'],
                    'country_code' => $cart->invoice['country'],
                    'town' => $cart->invoice['city'],
                ],
                'communication_numbers' => [
                    'mobile' => $cart->invoice['phone'],
                    'email' => $cart->invoice['email'],
                ],
                'extra_info' => [
                    [
                        'name' => 'ORDERCLOSED',
                        'value' => 'NO',
                    ],
                    [
                        'name' => 'ORDERAMOUNT',
                        'value' => $cart->totalPricePay->printValue(2),
                    ],
                    [
                        'name' => 'ORDERCURRENCY',
                        'value' => $cart->invoice['currency'],
                    ],
                    [
                        'name' => 'IP',
                        // 'value' => $_SERVER['REMOTE_ADDR'],
                        'value' => explode(',', SymfonyBridge::getCurrentRequest()->getClientIp())[0],
                    ],
                ],
            ],
        ];

        $uid = uniqid(null, true);
        $this->insertSQL('intrum_requests', ['uid' => $uid, 'type' => static::$REQUEST_ENQUIRY_CREDIT_ASSESSMENT]);
        $requestID = sqlInsertId();

        $dom = new \DOMDocument('1.0', 'UTF-8');

        /* @var $request Request */
        $request = $dom->appendChild(new Request());

        $request->setVersion('1.00');
        $request->setClientId($this->config['clientId']);
        $request->setUserID($this->config['userID']);
        $request->setPassword($this->config['password']);
        $request->setEmail($this->config['email']);
        $request->setRequestId($uid);

        $request->createRequest($data);
        $requestXML = $dom->saveXML();
        $this->updateSQL('intrum_requests', ['request' => $requestXML], ['id' => $requestID]);

        $transport = new TransportV0017();
        $transport->setMode($this->config['mode'] ?? 'test');
        $responseRequest = $transport->sendRequest($requestXML);

        $successful = false;
        try {
            $successful = $this->checkRawResponse($responseRequest, $requestID);
        } finally {
            $this->updateSQL('intrum_requests', [
                'response' => $responseRequest,
                'successful' => $successful,
            ], ['id' => $requestID]);

            $cart->setData($this->class.'_enquiryCreditRequest', $requestID);
            $cart->setData($this->class.'_hash', $hash);
        }
    }

    private function createHash(array $data)
    {
        array_multisort($data);

        return md5(json_encode($data));
    }

    public static function isEnabled($className)
    {
        $cfg = Config::get();

        if (empty($cfg['Modules']['payments'][$className])) {
            return false;
        }

        return true;
    }
}
