<?php

namespace App\Http\Controllers\Frontend;

use App\Exceptions\PaymentsConfigurationException;
use App\Exceptions\PaymentsIssueException;
use App\Exceptions\PaymentsUnavailableException;
use App\Exceptions\ResourseNotFoundException;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Tobuli\Entities\BillingPlan;
use Tobuli\Helpers\Payments\Payments;
use Illuminate\Support\Facades\Config;
use Tobuli\Repositories\BillingPlan\BillingPlanRepositoryInterface as BillingPlanRepo;
use Tobuli\Services\PermissionService;


class PaymentsController extends Controller
{
    private $permissionService;

    /**
     * PaymentsController constructor.
     * @param PermissionService $permissionService
     */
    public function __construct(PermissionService $permissionService)
    {
        parent::__construct();

        $this->permissionService = $permissionService;
    }

    /**
     * @param $gateway
     * @param $plan_id
     * @return mixed
     */
    public function pay($gateway, $plan_id)
    {
        $plan = BillingPlan::find($plan_id);

        if (empty($plan))
            return Redirect::route('payments.subscriptions')->with(['message' => trans('front.plan_not_found')]);

        try {
            return (new Payments($gateway))->pay($this->user, $plan);
        } catch (\Exception $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => $exception->getMessage()]);
        }
    }

    /**
     * @param Request $request
     * @param $gateway
     * @return mixed
     */
    public function payCallback(Request $request, $gateway)
    {
        try {
            return (new Payments($gateway))->payCallback($request);
        } catch (\Exception $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => $exception->getMessage()]);
        }
    }

    /**
     * @param $gateway
     * @param $plan_id
     * @return mixed
     */
    public function subscribe($gateway, $plan_id)
    {
        $plan = BillingPlan::find($plan_id);

        if (empty($plan))
            return Redirect::back()->with(['message' => trans('front.plan_not_found')]);

        try {
            return (new Payments($gateway))->subscribe($this->user, $plan);
        } catch (PaymentsIssueException $exception) {
            return Redirect::route('payments.gateways', $plan->id)->with(['message' => $exception->getMessage()]);
        } catch (PaymentsUnavailableException $exception) {
            return Redirect::route('payments.gateways', $plan->id)->with(['message' => $exception->getMessage()]);
        }
    }

    /**
     * @param Request $request
     * @param $gateway
     * @return mixed
     */
    public function subscribeCallback(Request $request, $gateway)
    {
        try {
            return (new Payments($gateway))->subscribeCallback($request);
        } catch (PaymentsIssueException $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => $exception->getMessage()]);
        } catch (PaymentsUnavailableException $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => $exception->getMessage()]);
        }
    }

    /**
     * Success route after payment.
     *
     * @return mixed
     */
    public function success()
    {
        return Redirect::route('payments.subscriptions')->with('success', trans('front.payment_received'));
    }

    /**
     * Cancel route if anything goes wrong.
     *
     * @return mixed
     */
    public function cancel()
    {
        return Redirect::route('payments.subscriptions')->with('message', trans('front.payment_canceled'));
    }

    /**
     * Select subscription plan view.
     *
     * @param BillingPlanRepo $billingPlanRepo
     * @return array|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function subscriptions(BillingPlanRepo $billingPlanRepo)
    {
        if ( ! settings('main_settings.enable_plans'))
            return Redirect::route('home');

        $permissions = $this->permissionService->group(
            $this->permissionService->getByManagerRole()
        );

        $plans = $billingPlanRepo->getWhere(['visible' => true], 'objects', 'asc');

        return view('front::Subscriptions.renew')->with(compact('plans', 'permissions'));
    }

    /**
     * Select gateway view.
     *
     * @param $plan_id
     * @return mixed
     */
    public function selectGateway($plan_id)
    {
        if (config('tobuli.type') == 'public') {
            $url = config('tobuli.frontend_subscriptions') . "?email=" . base64_encode(auth()->user()->email);

            return Redirect::to($url);
        }

        $plan = BillingPlan::find($plan_id);

        if (empty($plan))
            throw new ResourseNotFoundException('front.plan_not_found');

        if ($plan->isFree())
            return Redirect::route('payments.pay', ['gateway' => 'free', 'plan' => $plan->id]);

        $visible  = [];
        $gateways = settings('payments.gateways');

        foreach (config('payments') as $gateway => $config) {
            if (( ! $config['visible']) || ( ! $gateways[$gateway]))
                continue;

            $visible[] = $gateway;
        }

        return view('front::Subscriptions.gateways', [
            'gateways' => $visible,
            'plan_id'  => $plan->id,
        ]);
    }

    /**
     * Redirects to payment method.
     *
     * @param Request $request
     * @return mixed
     */
    public function checkout(Request $request)
    {
        if ( ! settings('payments.gateways.' . $request->gateway)) {
            return Redirect::back();
        }

        try {
            return (new Payments($request->gateway))->checkout($request->plan_id);
        } catch (PaymentsUnavailableException $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => $exception->getMessage()]);
        } catch (\Exception $exception) {
            return Redirect::route('payments.subscriptions')->with(['message' => trans('front.payments_service_unavailable')]);
        }
    }

    /**
     * Checks gateway configuration.
     *
     * @param Request $request
     * @param $gateway
     * @return \Illuminate\Http\JsonResponse
     */
    public function isConfigCorrect(Request $request, $gateway)
    {
        try {
            (new Payments($gateway))->isConfigCorrect($request);
        } catch (PaymentsConfigurationException $exception) {
            return response()->json(['status' => 0, 'error' => $exception->getMessage()]);
        }

        return response()->json(['status' => 1]);
    }

    /**
     * Modal for gateways specific information.
     *
     * @param $gateway
     * @return array|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function gatewayInfo($gateway)
    {
        return view('Admin.Billing.Gateways.Info.' . $gateway);
    }
}
