<?php

namespace Tobuli\Helpers\Payments\Gateways;


use App\Exceptions\PaymentsConfigurationException;
use App\Exceptions\PaymentsIssueException;
use App\Exceptions\PaymentsUnavailableException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\RequestOptions;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Response;
use Tobuli\Entities\Subscription;

class MobileDirectDebitGateway extends PaymentGateway implements PaymentGatewayInterface
{
    private $client;

    private $config;

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

        $this->client = new Client();
    }

    public function pay($user, $plan)
    {
        return $this->subscribe($user, $plan);
    }

    public function payCallback(Request $request)
    {
        return $this->subscribeCallback($request);
    }

    public function subscribe($user, $plan)
    {
        $referenceNo = $this->getReferenceNo();
        $phone = request('phone');

        $data = $this->makePaymentData($plan, $referenceNo, $phone);

        try {
            $responese = $this->call('POST', 'mobiledebit/create/mandate', $data);
        } catch (\Exception $e) {
            throw new PaymentsUnavailableException();
        }

        if (empty($responese['responseCode']))
            throw new PaymentsUnavailableException();

        if ( ! in_array($responese['responseCode'], ['01', '03']))
            throw new PaymentsIssueException($responese['responseMessage']);

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

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

    public function subscribeCallback(Request $request)
    {
        $referenceNo = $request->get('thirdPartyReferenceNo');

        $subscription = Subscription::where('gateway_id', $referenceNo)->first();

        if ( ! $subscription)
            throw new \Exception('Subscription not found for activation!');

        $this->activateSubscription($referenceNo);

        return Response::json([
            "responseCode" => "01",
            "responseMessage" => "Callback Successful."
        ]);
    }

    public function checkout($plan_id)
    {
        return view('front::Subscriptions.Gateways.mobile_direct_debit')->with([
            'plan_id'    => $plan_id,
            'gateway'    => $this->gatewayName(),
        ]);
    }

    public function isConfigCorrect(Request $request)
    {
        try {
            $responese = $this->call('POST', 'mobiledebit/create/mandate', [
                "apiKey" => $this->config['api_key'],
                "merchantId" => $this->config['merchant_id'],
                "productId" => $this->config['product_id'],
                "clientPhone" => '1111111111',
                "thirdPartyReferenceNo" => $this->getReferenceNo(),
                "amountToDebit" => "1.00",
                "frequencyType" => "Daily",
                "frequency" => "1",
            ]);
        } catch (\Exception $e) {
            throw new PaymentsConfigurationException($e->getMessage());
        }

        return true;
    }

    public function isSubscriptionActive($subscription)
    {
        try {
            $_subscription = $this->getSubscription($subscription);
        } catch (\Exception $e) {
            return false;
        }

        if ( ! $_subscription)
            return false;

        return true;
    }

    public function cancelSubscription($subscription)
    {
        try {
            $_subscription = $this->getSubscription($subscription);

            $this->call('POST', 'mobiledebit/cancel/mandate', [
                "merchantId" => $this->config['merchant_id'],
                "productId" => $this->config['product_id'],
                "clientPhone" => $_subscription['clientPhone'],
                //"mandateId" => $_subscription['mandateId'],
                "apiKey" => $this->config['api_key'],
            ]);
        } catch (\Exception $exception) {
            return false;
        }

        return true;
    }

    private function getSubscription($subscription)
    {
        try {
            $response = $this->call('GET', "mobiledebit/mandate/status/{$subscription->gateway_id}");
        } catch (\Exception $exception) {
            return null;
        }

        if (empty($response['clientPhone']))
            return null;

        return $response;
    }

    private function makePaymentData($plan, $referenceNo, $phone)
    {
        switch ($plan->duration_type) {
            case 'days':
                $frequencyType = 'Daily';
                break;
            case 'months':
                $frequencyType = 'Monthly';
                break;
            case 'years':
                $frequencyType = 'Annually';
                break;
            default:
                $frequencyType = null;
        }

        return [
            "apiKey" => $this->config['api_key'],
            "merchantId" => $this->config['merchant_id'],
            "productId" => $this->config['product_id'],
            "clientPhone" => $phone,
            "thirdPartyReferenceNo" => $referenceNo,
            "amountToDebit" => $plan->price,
            "frequencyType" => $frequencyType,
            "frequency" => $plan->duration_value,
            "debitDay" => "1",
        ];
    }

    private function getReferenceNo()
    {
        return "mdd_" . str_random(16);
    }

    private function call($method, $endpoint, $data = [])
    {
        $url = str_finish($this->config['url'], '/');

        try {
            $response = $this->client->request($method, $url . $endpoint, [
                RequestOptions::JSON => $data
            ]);

            $result = json_decode($response->getBody(), true);

            file_put_contents(storage_path('logs/mobile_direct_debit.log'), $response->getBody() . "\n", FILE_APPEND);
        } catch (\Exception $e) {
            throw new PaymentsUnavailableException();
        }

        return $result;
    }
}