<?php

namespace Tobuli\Helpers\Payments\Gateways;

use Adyen\Client;
use Adyen\Environment;
use Adyen\Service\Checkout;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;


class AdyenGateway extends PaymentGateway implements PaymentGatewayInterface
{
    const REDIRECT = 'RedirectShopper';
    const AUTHORIZED = 'Authorised';

    private $config;
    private $client;
    private $checkoutService;

    public function __construct()
    {
        $this->config = settings('payments.adyen');

        $this->client = new Client();
        $this->client->setXApiKey($this->config['api_key']);
        $this->client->setEnvironment(Environment::TEST); // TODO SET LIVE
        $this->checkoutService = new Checkout($this->client);
    }

    public function pay($user, $plan)
    {
        $reference = uniqid('ay', true);

        $result = $this->checkoutService([
            'paymentMethod'   => array_except(request()->all(), ['_token']),
            'merchantAccount' => $this->config['merchant_account'],
            'countryCode'     => $this->config['country'],
            'reference'       => $reference,
            'returnUrl'       => route('payments.pay_callback', ['gateway' => $this->gatewayName()]),
            'amount'          => [
                'currency' => $this->config['currency'],
                'value'    => $plan->price,
            ],
        ]);

        $this->storeSubscription($user, $plan, $reference);

        if ($result['resultCode'] === self::REDIRECT) {
            return Redirect::away($result['redirect']['url']);
        }

        if ($result['resultCode'] !== self::AUTHORIZED) {
            return Redirect::route('payments.cancel');
        }

        // no way to get payment details after this
        // and if above condition is satisfied it is already done
        $this->activateSubscription($reference);

        return Redirect::route('payments.success');
    }

    public function payCallback(Request $request)
    {
        if ($request->resultCode !== self::AUTHORIZED) {
            return Redirect::route('payments.cancel');
        }

        $result = $this->checkoutService->paymentsDetails([
            'details' => ['payload' => $request->payload],
        ]);

        $this->activateSubscription($result['merchantReference']);

        return Redirect::route('payments.success');
    }

    public function subscribe($user, $plan)
    {
        $result = $this->checkoutService->payments([
            'reference'        => uniqid('adyen', true),
            'paymentMethod'    => array_except(request()->all(), ['_token']) + ['storeDetails' => true],
            'shopperReference' => 5,
            'returnUrl'        => route('payments.subscribe_callback', ['gateway' => $this->gatewayName()]),
            'merchantAccount'  => $this->config['merchant_account'],
            'amount'           => [
                'currency' => $this->config['currency'],
                'value'    => 1000,
            ],
        ]);

         $this->storeSubscription($user, $plan, $result['additionalData']['recurring.recurringDetailReference']);

        if ($result['resultCode'] === self::REDIRECT) {
            return Redirect::away($result['redirect']['url']);
        }

        if ($result['resultCode'] !== self::AUTHORIZED) {
            return Redirect::route('payments.cancel');
        }

        return Redirect::route('payments.subscribe_callback', [
            'gateway' => $this->gatewayName(),
            'shopperReference' => $result['additionalData']['recurring.shopperReference'],
        ]);
    }

    public function subscribeCallback(Request $request)
    {
        if ($request->has('payload')) {
            if ($request->resultCode !== self::AUTHORIZED) {
                return Redirect::route('payments.cancel');
            }

            $result = $this->checkoutService->paymentsDetails([
                'details' => ['payload' => $request->payload],
            ]);

            $this->activateSubscription($result['merchantReference']);

            return Redirect::route('payments.success');
        }

        $result = (new \Adyen\Service\Recurring($this->client))->listRecurringDetails([
            'merchantAccount'  => $this->config['merchant_account'],
            'shopperReference' => $request->shopperReference,
        ]);

        if ( ! isset($result['details'][0]['RecurringDetail']['recurringDetailReference'])) // TODO INVESTIGATE [0]
            return Redirect::route('payments.cancel');

        // recurringDetailReference always the same depending on shopperReference, potential dublicates in DB
        $this->activateSubscription($result['details'][0]['RecurringDetail']['recurringDetailReference']);

        return Redirect::route('payments.success');
    }

    public function checkout($plan_id)
    {
        $result = $this->checkoutService->paymentMethods([
            'merchantAccount' => $this->config['merchant_account'],
            'countryCode'     => $this->config['country'],
            'amount'          => ['currency' => $this->config['currency'], 'value' => 1],
        ]);

        return view('front::Subscriptions.Gateways.adyen')->with([
            'plan_id'         => $plan_id,
            'gateway'         => $this->gatewayName(),
            'origin_key'      => $this->config['origin_key'],
            'payment_methods' => $result['paymentMethods'],
        ]);
    }

    public function isConfigCorrect(Request $request)
    {
        try {
            $this->checkoutService->paymentMethods([
                'merchantAccount' => $this->config['merchant_account'],
                'countryCode'     => $this->config['country'],
                'amount'          => [
                    'currency' => $this->config['currency'],
                    'value' => 1
                ],
            ]);
        } catch (\Exception $e) {
            return $e->getMessage();
        }

        return true;
    }

    public function isSubscriptionActive($subscription)
    {
        // TODO: Implement isSubscriptionActive() method.
    }

    public function cancelSubscription($subscription)
    {
        // TODO: Implement cancelSubscription() method.
    }
}