<?php

namespace App\Http\Controllers\Frontend\User;

use App\Http\Controllers\Controller;
use App\Models\Auth\Invite;
use App\Models\Auth\User;
use App\Models\Auth\UserPendingData;
use App\Models\Forums\ForumChannel;
use App\Models\Lab;
use App\Models\Lookups\Institution_lookup;
use App\Models\Lookups\Position_lookup;
use App\Models\Lookups\Prefix_lookup;
use App\Models\Lookups\Research_focus_lookup;
use App\Models\Lookups\Stripe_plans;
use Auth;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Laravel\Cashier\Exceptions\IncompletePayment;
use Sabberworm\CSS\Value\Value;
use Stripe\Exception\InvalidRequestException;
use Stripe\PromotionCode;
use Stripe\Stripe;

/**
 * Class AccountController.
 */
class AccountController extends Controller
{
    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function index()
    {

        $subscriptionDeets = false;
        if (auth()->user()->current_active_subscriptions->count()) {
            if(auth()->user()->asStripeCustomer()->subscriptions){
                $subscriptionDeets = collect(auth()->user()->asStripeCustomer()->subscriptions->data)->last();
            }
        }

        $prefix_lookup = Prefix_lookup::all();
        $institution_lookup = Institution_lookup::all();
        $position_lookup = Position_lookup::all();
        $research_lookup = Research_focus_lookup::all();
// dd(auth()->user()->labs);
        return view('frontend.user.account')
            ->with('subscriptionDeets', $subscriptionDeets)
            ->with('prefix_lookup', $prefix_lookup)
            ->with('position_lookup', $position_lookup)
            ->with('institution_lookup', $institution_lookup)
            ->with('research_lookup', $research_lookup);
    }

    /**

     *All other stuff is handled by webhooks
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public
    function showNewPlanForm(Request $request)
    {
        // make them a customer if not already
        $stripeCustomer = auth()->user()->createOrGetStripeCustomer();
        $plan = auth()->user()->current_active_subscriptions->count() ? Stripe_plans::where(['stripe_plan' => auth()->user()->current_active_subscriptions->last()->stripe_plan])->first() : false;
        $context = 'changeplan';
//// adapted from https://laravel.com/docs/7.x/billing
        $intent = auth()->user()->createSetupIntent();
        return view('frontend.user.subscription')
            ->with('intent', $intent)
            ->with('context', $context)
            ->with('plan', $plan);
    }

    /**
     * Accept the change plan, pass details to the checkout. Later, handle updates through webhooks
     *
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|void
     */
    function acceptNewPlanForm(Request $request)
    {
        // process the payment, sign the user up to the selected plan.
        //return $request->user()->redirectToBillingPortal();
      //  if ($request['payment_frequency']) {
            // get the actual plan, along with the price ID

            $plan = Stripe_plans::find($request['stripe_plan_id']);
            //  dd($plan->stripe_plan);
//        } else {
//            $plan = auth()->user()->current_active_subscriptions->count() ? Stripe_plans::where(['stripe_plan' => auth()->user()->current_active_subscriptions->last()->stripe_plan])->first() : false;
//            $context = 'changeplan';
//            $intent = auth()->user()->createSetupIntent();
//            return view('frontend.user.subscription')
//                ->with('intent', $intent)
//                ->with('context', $context)
//                ->with('plan', $plan)
//                ->withErrors('Payment frequency is required');
//        }
        // save some pending data
        $pending_data = array('incomplete' => true);
        //also set some way of retrieving the lab name
        if ($plan->selector == 'lab') {
            $pending_data['lab_name'] = $request['lab_name'];
        }
        // save the roles to be fixed up later
        $roles = [$plan->role];
        if (auth()->user()->hasRole('lab member')) {
            $roles[] = 'lab member';
        }
        if (auth()->user()->hasRole('administrator')) {
            $roles[] = 'administrator';
        }
        $pending_data['roles'] = $roles;
        $data = new UserPendingData(['pending_data' => \json_encode($pending_data)]);
        auth()->user()->pending_data()->save($data);

        // go to the confirm and checkout page- @TODO pass success, failure and other params to, for example create labs
        $checkout = auth()->user()->newSubscription($plan->name, $plan->stripe_plan)->allowPromotionCodes()->checkout([
            'success_url' => route('frontend.user.changeplansuccess'),
            'cancel_url' => route('frontend.user.changeplanfailure'),
        ]);
        //$checkout = auth()->user()->newSubscription($plan->name, $plan->stripe_plan)->add();
        //dd($checkout);
        return $checkout;

//        return view('frontend.user.checkout', [
//            'checkout' => $checkout,
//            'plan'=>$plan
//        ]);

        // attempt a subscription.
//        try {
//            // does the user already have a subscription?
//            if (auth()->user()->current_active_subscriptions->count()) {
//                // swap the subscription
//                // get the subscription
//                $subscription = auth()->user()->subscription(auth()->user()->current_active_subscriptions->last()->name);
//// get the subscription *item*. Dunno why this is like it is
//                $item = $subscription->findItemOrFail(auth()->user()->current_active_subscriptions->last()->stripe_plan);
//// swap the subscription
//                $item->swap($plan->stripe_plan);
//                // update the subscription name
//                $subscription['name'] = $plan->name;
//                $subscription->save();
//                // dd(auth()->user()->current_active_subscriptions->last());
//                \Session::flash('flash_success', 'Your subscription has been updated.');
//
//            } else {
//                // does the user have a current incomplete subscription? Then redirect them to the payment page to complete the transaction
//                if (auth()->user()->current_incomplete_subscriptions->count()) {
//                    return redirect()->route(
//                        'cashier.payment',
//                        [auth()->user()->current_incomplete_subscriptions->last()->latestPayment()->id->payment->id, 'redirect' => route('frontend.user.account')]
//                    );
//                }
//                // if none of the above are true, make a new one
//                try {
//                    // attempt payment
//                    // first, set the user up as a stripe customer if not already
//                    $stripeCustomer = auth()->user()->createOrGetStripeCustomer();
//                    // then, set the payment method if not already existing
//                    if (!auth()->user()->defaultPaymentMethod()) {
//                        auth()->user()->updateDefaultPaymentMethod($request['stripePaymentMethod']);
//                    }
//
//                    // gotta be a more elegant way of doing this
//                    $checkout = auth()->user()->allowPromotionCodes()->newSubscription('default', 'price_1IwQpTLzWoLInG3Ml70cVJ9L')->checkout([
//                        'success_url' => route('frontend.index'),
//                        'cancel_url' => route('frontend.index'),
//                    ]);
//                    return view('frontend.user.checkout',[
//                        'checkout' => $checkout,
//                    ]);
//
////                        auth()->user()->newSubscription($plan->name, $plan->stripe_plan)->create(auth()->user()->defaultPaymentMethod()->id, [
////                            'email' => auth()->user()->email,
////                        ]);
////
//                    \Session::flash('flash_success', 'Your subscription has been updated.');
//                } catch (IncompletePayment $exception) {
//                    // redirect an if payment fails, ultimately to account page
//                    // set some data in the subscriptions table variable to flag that this has happened and to hold some data
//                    $pending_data = array('incomplete' => true);
//                    //also set some way of retrieving the lab name
//                    if ($plan->selector == 'lab') {
//                        $pending_data['lab_name'] = $request['lab_name'];
//                    }
//                    // save the roles to be fixed up later
//                    $roles = [$plan->role];
//                    if (auth()->user()->hasRole('lab member')) {
//                        $roles[] = 'lab member';
//                    }
//                    if (auth()->user()->hasRole('administrator')) {
//                        $roles[] = 'administrator';
//                    }
//                    $pending_data['roles'] = $roles;
//                    $data = new UserPendingData(['pending_data' => \json_encode($pending_data)]);
//                    auth()->user()->pending_data()->save($data);
//
//                    //We'll fix up roles when we're next at the account or home page
//                    return redirect()->route(
//                        'cashier.payment',
//                        [$exception->payment->id, 'redirect' => route('frontend.user.account')]
//                    );
//                }
//            }
//
//            //OK. We've paid the normal way, so let's just keep going...
//            // set a new role based on the plan, but preserving the lab role if it's there
//            $roles = [$plan->role];
//            if (auth()->user()->hasRole('lab member')) {
//                $roles[] = 'lab member';
//            }
//            auth()->user()->syncRoles($roles);
//
//            // are they adding a lab subscription? in which case, set up a lab here
//            if ($plan->selector == 'lab') {
//                // does this user already have a lab (possible if the user was previously a lab admin but dropped back)
//                if (auth()->user()->my_lab) {
//                    //  dd(auth()->user()->my_lab);
//                    Lab::find(auth()->user()->my_lab->id)->update(['name' => $request['lab_name']]);
//                } else {
//                    // make a new lab, make this person an admin
//                    $lab = new Lab(['name' => $request['lab_name']]);
//                    $lab->save();
//                    $lab->members()->sync(array(auth()->user()->id => array('admin' => 'true')));
//                    // make a lab forums
//                    // announcements
//                    $annoucements = new ForumChannel(['name' => 'Announcements', 'user_id' => auth()->user()->id, 'lab_id' => $lab->id, 'is_announcement_forum' => 1]);
//                    $annoucements->save();
//                    // general
//                    $general = new ForumChannel(['name' => 'General', 'user_id' => auth()->user()->id, 'lab_id' => $lab->id]);
//                    $general->save();
//                }
//            }
//
//        } catch (InvalidRequestException $e) {
//            // try it again
////            dd($e->getMessage());
//            $plan = auth()->user()->current_active_subscriptions->count() ? Stripe_plans::where(['stripe_plan' => auth()->user()->current_active_subscriptions->last()->stripe_plan])->first() : false;
//            $context = 'changeplan';
//            $intent = auth()->user()->createSetupIntent();
//            return view('frontend.user.subscription')
//                ->with('intent', $intent)
//                ->with('context', $context)
//                ->with('plan', $plan)
//                ->withErrors('There was a problem: ' . $e->getMessage());
//        }

        // go home, we're done because everything fell over in a screaming heap
        \Session::flash('flash_danger', 'Your subscription did not complete.');
        return redirect()->route('frontend.user.account');

    }

    // feedback for subscription checkout success and failure
    //@TODO check to see that there's a successful plan from teh webhook, if not then throw a little message
    public function showChangePlanFormSuccess()
    {
        \Session::flash('flash_success', 'Your subscription has been updated. If you don\'t see your changes straight away, please refresh the page');
        return redirect()->route('frontend.user.account');
    }

    // if failure,
    public function showChangePlanFormFailure(Request $request)
    {
        //dd($request);
        // clean up pending data
        foreach (Auth::user()->pending_data as $pending_data) {
            $pending_data->delete();
        }
        \Session::flash('flash_danger', 'Your subscription did not complete.');
        return redirect()->route('frontend.user.account');
    }


    /**
     * Get plan details as a JSON array
     * @param Request $request
     * @return array
     */
    public
    function getPlanDetails(Request $request)
    {
        //@TODO use https://laravel-news.com/laravel-exchange-rates-api-package to get converted value
        $data = [];
        $data['level_plans'] = Stripe_plans::where(['selector' => $request['subscription_level']])->whereNull('archived')->whereNull('hide_from_app')->get();
        if ($request['payment_frequency']) {
            $data['selected_plan'] = Stripe_plans::where(['selector' => $request['subscription_level'], 'period' => $request['payment_frequency']])->whereNull('archived')->first();
        }
        return $data;
    }

    /**
     * Show the change payment method form. Hide the change plan bit
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public
    function showChangePaymentMethodForm(Request $request)
    {
        $stripeCustomer = auth()->user()->createOrGetStripeCustomer();

// adapted from https://laravel.com/docs/7.x/billing
        $intent = auth()->user()->createSetupIntent();
        return view('frontend.user.update_payment_method')
            ->with('intent', $intent)
            ->with('customer', $stripeCustomer);
    }

    /**
     * Accept the change payment method form
     * @param Request $request
     */
    public
    function acceptChangePaymentMethodForm(Request $request)
    {
        try {
            auth()->user()->updateDefaultPaymentMethod($request['stripePaymentMethod']);
//            return array(
//                'status' => 0,
//            );
            \Session::flash('flash_success', 'Your payment details have been updated');
            return redirect()->route('frontend.user.account');

        } catch (\Error $e) {

            $stripeCustomer = auth()->user()->createOrGetStripeCustomer();

// adapted from https://laravel.com/docs/7.x/billing
            $intent = auth()->user()->createSetupIntent();
            return view('frontend.user.update_payment_method')
                ->with('intent', $intent)
                ->with('customer', $stripeCustomer)
                ->withErrors('There was a problem: ' . $e->getMessage());
        }
    }

    /**
     * Show the cancel plan form
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public
    function showCancelPlanForm(Request $request)
    {
        $plan = auth()->user()->current_active_subscriptions ? Stripe_plans::where(['stripe_plan' => auth()->user()->current_active_subscriptions->last()->stripe_plan])->first() : false;
        return view('frontend.user.cancelplan')
            ->with('plan', $plan);
    }

    /**
     * Accept the change payment method form
     * @param Request $request
     */
    public
    function acceptCancelPlanForm(Request $request)
    {
        $plan = Stripe_plans::where(['stripe_plan' => auth()->user()->subscriptions->first()->stripe_plan])->first();
        try {
            // cancel the subscription

            auth()->user()->subscription(auth()->user()->subscriptions->first()->name)
                ->cancelNow();
            // drop back to free tier role...
            // remove role,
            // add base user role
            // but preserving the lab role if it's there
            //20200525 @TODO is this redundant?
            $roles = ['user'];
            if (auth()->user()->hasRole('lab member')) {
                $roles[] = 'lab member';
            }
            auth()->user()->syncRoles($roles);
            //@TODO make all user's boards read only
            \Session::flash('flash_success', 'Your subscription has been updated.');
            return redirect()->route('frontend.user.account');
//            return array(
//                'status' => 0,
//            );
        } catch (\Error $e) {
            $plan = auth()->user()->current_active_subscriptions ? Stripe_plans::where(['stripe_plan' => auth()->user()->current_active_subscriptions->last()->stripe_plan])->first() : false;
            return view('frontend.user.cancelplan')
                ->with('plan', $plan)
                ->withErrors('There was an error:' . $e->getMessage());
//            return array(
//                'status' => 1,
//                'message' => $e->getMessage()
//            );
        }
    }


//    Show the form to collect data from a user who hasn't interacted with the system yet
//DEPRECATED
    public
    function showFirstLoginForm()
    {
        // is this from an invite?
        $invited = (Invite::where('email', auth()->user()->email)->get()->count() > 0);
        $prefix_lookup = Prefix_lookup::all();
        $institution_lookup = Institution_lookup::all();
        $position_lookup = Position_lookup::all();
        $research_lookup = Research_focus_lookup::all();
        return view('frontend.auth.firstlogin')
            ->with('prefix_lookup', $prefix_lookup)
            ->with('position_lookup', $position_lookup)
            ->with('institution_lookup', $institution_lookup)
            ->with('research_lookup', $research_lookup)
            ->with('invited', $invited);
    }

//    Accept the demographic parameters. If a user wants to pay, deal with it here
//DEPRCATED
    public
    function acceptFirstLoginPost(Request $request)
    {
        // Lookups: new if not exists. Probably a more elegant way to do this, but ut works
        if (isset($request['prefix_lookup_id'])) {
            if (!(Prefix_lookup::where('id', $request['prefix_lookup_id'])->exists())) {
                $new = Prefix_lookup::updateOrCreate(['text' => $request['prefix_lookup_id']]);
                $request['prefix_lookup_id'] = $new->id;
            }
        }

        if (isset($request['position_lookup_id'])) {
            if (!(Position_lookup::where('id', $request['position_lookup_id'])->exists())) {
                $new = Position_lookup::updateOrCreate(['text' => $request['position_lookup_id']]);
                $request['position_lookup_id'] = $new->id;
            }
        }

        if (isset($request['institution_lookup_id'])) {
            if (!Institution_lookup::find($request['institution_lookup_id'])) {
                $new = Institution_lookup::updateOrCreate(['text' => $request['institution_lookup_id']]);
                $request['institution_lookup_id'] = $new->id;
            }
        }

        if (isset($request['research_focus_lookup_id'])) {
            foreach ($request['research_focus_lookup_id'] as $item) {
                if (!(Research_focus_lookup::where('id', $item)->exists())) {
                    $new = Research_focus_lookup::updateOrCreate(['text' => $item]);
                    $request['research_focus_lookup_ids'] .= $new->id . ',';
                } else {
                    $request['research_focus_lookup_ids'] .= Research_focus_lookup::find($item)->id . ',';
                }
            }
            $request['research_focus_lookup_ids'] = rtrim($request['research_focus_lookup_ids'], ',');
        }

        $user = auth()->user()->update($request->only('first_name',
            'last_name',
            'prefix_lookup_id',
            'position_lookup_id',
            'institution_lookup_id',
            'research_focus_lookup_ids',
            'phone',
            'first_login'
        ));

        // are they adding a lab subscription? in which case, set up a lab here
        if (!$request['subscription_level'] || ($request['subscription_level'] == 'lab')) {
            // does this user already have a lab (possible if this process falls over)
            if (auth()->user()->my_lab) {
                auth()->user()->my_lab->name = $request['lab_name'];
                auth()->user()->my_lab->save();
            } else {
                // make a new lab, make this person an admin
                $lab = Lab::create(['name' => $request['lab_name']]);
                $lab->members()->sync(array(auth()->user()->id => array('admin' => 'true')));
            }
        }

        // stripe stuff
        // make the user into a stripa customer
        $stripeCustomer = auth()->user()->createOrGetStripeCustomer();

        // if they're choosing the freebie or if they're invited, then go straight home
        if (!$request['subscription_level'] || ($request['subscription_level'] == 'free')) {
            // let's lose the first login flag, go home
            auth()->user()->first_login = '';
            auth()->user()->save();
            return redirect()->to(route(home_route()));
        } else {
            // else
            // work out the subscription code here, show payment view
            $plan = Stripe_plans::where(['selector' => $request['subscription_level'], 'period' => $request['payment_frequency']])->first();

            //@TODO use https://laravel-news.com/laravel-exchange-rates-api-package to get converted value

// adapted from https://laravel.com/docs/7.x/billing
            $intent = auth()->user()->createSetupIntent();
            return view('frontend.auth.firstpay')
                ->with('intent', $intent)
                ->with('plan', $plan);
        }
    }

    public function removeCollaborator(Request $request)
    {
        $lab = Lab::find($request['labId']);
        $lab->members()->detach(['user_id' => $request['userId']]);
        return ['status' => 200];
    }

    public function makeCollaborator(Request $request)
    {
        $lab = Lab::find($request['labId']);
        $lab->members()->updateExistingPivot(['user_id' => $request['userId']], ['moderator' => $request['status']]);

        return ['status' => 200];
    }

    /////////////////////////////////////////////////////////////////////////////////////////////
    ///
    /// Stripe  functions
    ///
    /// //////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Validates a promo code. Adapted from https://dev.to/ku_suke/implementing-coupon-promocode-discount-in-stripe-laravel-cashier-3e1j
     * @param $code
     * @return false
     */
    public function validatePromocode(Request $request)
    {
        $code = $request['code'];
        try {
            $promoCodes = \Cache::remember('stripe-cache-promocodes', 600, function () {
                Stripe::setApiKey(\Config::get('cashier.secret'));
                return PromotionCode::all(["active" => true]);
            });
            //  dd($promoCodes);
            foreach ($promoCodes->data as $promoCode) {
                if ($code == $promoCode->code) {
                    // valid
                    if ($promoCode->coupon->valid) {
                        return ['id' => $promoCode->coupon->id, 'valid' => $promoCode->coupon->valid, 'percent_off' => $promoCode->coupon->percent_off, 'name' => $promoCode->coupon->name];
                    } else {
                        return ['error' => 'true', 'message' => 'Coupon has expired'];
                    }

                }
            }

            return ['error' => 'true', 'message' => 'Not a valid code'];
        } catch (\Exception $e) {

            return ['error' => 'true', 'message' => $e->getMessage()];
        }
    }

}
