<?php

namespace Mtc\Modules\Members\Http\Controllers;

use App\SubscriptionBundleType;
use Carbon\Carbon;
use DateTime;
use DateTimeInterface;
use Exception;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\App;
use Illuminate\View\View;
use Item;
use Mtc\Core\Models\Country;
use Mtc\Core\Models\CountryState;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Modules\Members\Classes\MemberManager;
use Mtc\Modules\Members\Models\Member;
use Mtc\Plugins\NewsletterSignup\Classes\Newsletter;
use Mtc\Plugins\NHS\Classes\NHSMember;
use Mtc\Plugins\NHS\Classes\Prescription;
use Mtc\Shop\Basket;
use Mtc\Shop\MedicalCondition;
use Mtc\Shop\Medication;
use Mtc\Shop\Order;
use MtcPharmacy\Bundles\Classes\BundleTypeItem;
use MtcPharmacy\Subscriptions\Classes\Subscription;
use MtcPharmacy\Subscriptions\Classes\SubscriptionItem;


class MembersController extends BaseController
{
    private Member $member;
    private $memberOrders;

    public function __construct()
    {
        $this->middleware(function ($request, $next) {
            $this->member = Auth::getLoggedInMember();

            if (!$this->member->id) {
                return redirect(route('members-login'));
            }
            return $next($request);
        });
    }

    /**
     * Member dashboard
     *
     * @return Factory|View
     */
    public function index()
    {
        $page_meta['title'] = config('app.name') . ' | Members Section';

        $orders = Order::query()
            ->with('items')
            ->where('paid', 1)
            ->where(function ($query) {
                $query->where('member', $this->member->id)
                    ->orWhereHas('info', function ($query) {
                        $query->where('email', $this->member->email);
                    });
            })
            ->orderBy('id', 'desc')
            ->get()
            ->map(function ($order) {
                $order->num_items = $order->items->sum('quantity');
                $order->status = Order::$statuses[$order->status];
                $order->date_long = Carbon::createFromFormat('Y-m-d H:i:s', $order->date)->format('j F Y');
                $order->date = Carbon::createFromFormat('Y-m-d H:i:s', $order->date)->format('d/m/Y');

                $order->can_reorder = true;

                /*
                 * Order categories
                 */
                $has_nhs_items = false;
                $has_online_doctor_items = false;
                $has_shop_items = false;

                foreach ($order->items as $item) {

                    if (!empty($item->assessment_id)) {
                        $has_online_doctor_items = true;
                    }

                    if (!empty($item->nhs_prescription)) {
                        $has_nhs_items = true;
                    }

                    if (empty($item->assessment_id) && empty($item->nhs_prescription)) {
                        $has_shop_items = true;
                    }
                }

                $order->has_shop_items = $has_shop_items;
                $order->has_nhs_items = $has_nhs_items;
                $order->has_online_doctor_items = $has_online_doctor_items;

                /*
                 * Get order postcode
                 */
                $addresses = $order->address->toArray();
                $shipping_postcode = false;
                $billing_postcode = false;

                foreach ($addresses as $address) {

                    if (!empty($address['type'])) {

                        if ($address['type'] == 'shipping') {

                            $shipping_postcode = $address['postcode'];

                        } elseif ($address['type'] == 'billing') {

                            $billing_postcode = $address['postcode'];
                        }

                    }

                }

                if (!empty($shipping_postcode)) {
                    $order->order_postcode = $shipping_postcode;
                } elseif (!empty($billing_postcode)) {
                    $order->order_postcode = $billing_postcode;
                }

                /*
                 * Order image
                 */
                $first_item = $order->items[0];
                $order->item_image = THEME_URL . '/images/placeholders/no-image.jpg';
                $order->no_image = true;

                if (!empty($first_item->item_id)) {

                    $temp_item = new Item();
                    $temp_item->Get_Item($first_item->item_id, true);
                    $item_images = collect($temp_item->images);

                    $item_image = $item_images->filter(function ($image) {
                        if (!empty($image['default'])) {
                            return $image;
                        }
                    })->first();

                    if (!empty($item_image['name'])) {
                        $order->item_image = $item_image['name'];
                        $order->no_image = false;
                    }
                }

                return $order;
            });


        /*
         * Tab navigation
         */
        $order_tabs = [
            'All' => [
                'data' => []
            ],
            'Online doctor' => [
                'data' => []
            ],
            'Shop' => [
                'data' => []
            ],
        ];


        /*
         * Build tab content
         */
        $limit = 3;

        foreach ($orders as $order) {

            if (count($order_tabs['All']['data']) < 4) {
                $order_tabs['All']['data'][] = $order;
            }

            if ($order->has_shop_items && count($order_tabs['Shop']['data']) <= $limit) {
                $order_tabs['Shop']['data'][] = $order;
            }

            if ($order->has_nhs_items && count($order_tabs['NHS prescriptions']['data']) <= $limit) {
                $order_tabs['NHS prescriptions']['data'][] = $order;
            }

            if ($order->has_online_doctor_items && count($order_tabs['Online doctor']['data']) <= $limit) {
                $order_tabs['Online doctor']['data'][] = $order;
            }

        }

        return template('members/index.twig', [
            'page_meta' => $page_meta,
            'name' => $this->member->addressBilling->firstname,
            'member' => $this->member,
            'orders' => $orders,
            'order_tabs' => $order_tabs,
            'success' => session()->has('success') ?
                session('success') :
                null,
        ]);
    }

    /**
     * Member orders
     *
     * @return Factory|View
     */
    public function orders()
    {
        $page_meta['title'] = config('app.name') . ' | Your Orders';

        $this->memberOrders = $this->member->orders()
            ->orderByDesc('id')
            ->get()
            ->filter(function($order) {
                if ($order->paid) {
                    return true;
                }

                $subscription =  $order->subscriptions->first();
                if ($subscription && $subscription->hasFailedPayment()) {
                    return true;
                }
                return false;
            });


        return template('/members/orders/index.twig', [
            'page_meta' => $page_meta,
            'member_orders' => $this->memberOrders
        ]);
    }

    /**
     * Member order
     *
     * @param $id
     * @return string
     */
    public function order($id): string
    {
        $page_meta['title'] = config('app.name') . ' | Order Details';

        $order = \Order::getById($id);

        if(!empty($order)) {
            $order->status = Order::$statuses[$order->status];

            $temp_order = Order::query()
                ->where('id', $id)
                ->first();

            $order->date_long = Carbon::createFromFormat('Y-m-d H:i:s', $temp_order->date)
                ->format('j F Y');
            $order->date = Carbon::createFromFormat('Y-m-d H:i:s', $temp_order->date)
                ->format('d/m/Y');
        }

        if ($this->member->id == 0 || ($order->member != $this->member->id && $order->info['email'] != $this->member->email)) {
            header("Location: " . route('members-orders', [], false));
            exit();
        }

        $items = $order->getItems();

        foreach ($items as $key => $line) {
            $item = new Item();
            $item->Get_Item($line['item_id']);

            // get image, checked if exists in item class
            $image = $item->get_basket_image();

            $items[$key]['item_url'] = $item->Generate_URL('');
            $items[$key]['image'] = $image;
        }

// Get order info previously called via class methods
        $order->deliveryinfo = $order->getDelivery();

        $totals = [
            'subtotal' => $order->getSubtotalCost(),
            'total' => $order->getTotalCost(),
        ];


        return template('/members/orders/order.twig', [
            'page_meta' => $page_meta,
            'member_id'=> $this->member->id,
            'order'   => $order,
            'totals'  => $totals,
            'items'   => $items,
            'tracking_events' => [],
        ]);
    }

    /**
     * Reorder
     *
     * @param $id
     * @return void
     */
    public function reorder($id): void
    {
        $basket = new \Basket();
        $basket->Go_Basket();
        $order = Order::query()
            ->with(['items.item', 'info'])
            ->find($id);

        

        if (
            empty($order) ||
            (
                $order->member != $this->member->id &&
                $order->info->email != $this->member->email
            )
        ) {
            header("Location: " . route(
                    'members-orders',
                    [
                        'error' => 'cannot_find',
                    ],
                    false)
            );
            exit();
        }

        $order->items->each(function ($order_item) {
            // If an item is out of stock, redirect to item page
            if (!empty($order_item->item->id)) {
                $item = new Item($order_item->item->id);
                if ($order_item->item->sizes->isEmpty()) {
                    if ($order_item->item->stock === 0) {
                        header('location: ' . $item->url);
                        exit;
                    }
                } else {
                    if ($order_item->item_size->stock === 0) {
                        header('location: ' . $item->url);
                        exit;
                    }
                }
            }
        });

        $assessments = [];
        $order->items
            ->each(function ($item) use ($basket, &$assessments) {
                if ($item->item->form_id > 0) {
                    $assessments[] = [
                        'form_id' => $item->item->form_id,
                        'p' => $item->item_id,
                        's' => $item->sizeid,
                        'q' => $item->quantity
                    ];
                } elseif ($item->item->id) {
                    $basket->Add_Item([
                        'id' => $item->item_id,
                        'size_id' => $item->sizeid,
                        'size' => $item->size,
                        'PLU' => $item->PLU,
                        'quantity' => $item->quantity
                    ]);
                }
            });

        $url = '/shop/checkout/basket.php';

        if (count($assessments)) {
            $url = route('assessment-form', $assessments[0], false);
        }

        header("Location: " . $url);
        exit();
    }

    /**
     * Member account
     *
     * @return string
     */
    public function account(): string
    {
        $page_meta['title'] = config('app.name') . ' | My Account';

        if ($this->member->nhs_member && $this->member->nhs_member->dob == '0000-00-00') {
            $this->member->nhs_member->dob = '';
        }

        if (!empty($this->member->dob)) {
            $dobDate = Carbon::parse($this->member->dob);
            $this->member->dob_date = $dobDate->format('d');
            $this->member->dob_month = $dobDate->format('m');
            $this->member->dob_year = $dobDate->format('Y');
        }

        $settings['PAF_ENABLED'] = false;

        return template('members/details.twig', [
            'page_meta' => $page_meta,
            'member_id'=> $this->member->id,
            'member' => $this->member,
            'countries' => Country::getFullCountryList(),
            'state_list' => CountryState::getStateList("US"),
            'self' => $_SERVER['REQUEST_URI'],
            'titles' => Member::$titles,
            'genders' => Member::$genders,
            'paf_enabled' => $settings['PAF_ENABLED'],
            'dob' => Member::getDobOptions(),
            'newsletter' => Newsletter::checkIfExists($this->member->email),
        ]);
    }

    /**
     * Save account
     */
    public function accountStore(Request $request)
    {
        $success = [];
        $errors = [];

        $memberManager = new MemberManager();
        $data = $request->all();
        if ($memberManager->save($data, $this->member, [
            MemberManager::PARAM_CHECK_SESSION => true,
        ])) {
            if (!empty($data['newsletter'])) {
                Newsletter::signUp($data['email'], [
                    'first_name' => $data['billing_firstname'],
                    'last_name' => $data['billing_lastname'],
                    'skip_double_opt_in' => true,
                ]);
            } else {
                Newsletter::unsubscribe($data['email']);
            }
            $success['message'] = '<p class="success">We have successfully saved your details</p>';
        } else {
            $errors = $memberManager->getErrors();
        }

        return json_encode([
            'errors' => $errors,
            'success' => $success,
        ]);
    }

    /**
     * Member account
     *
     * @return string
     */
    public function healthProfile(): string
    {
        $page_meta['title'] = config('app.name') . ' | My Health Profile';

        $this->member->medications_json = empty($this->member->medications) ? '' : clean_page(implode(',', (array)json_decode($this->member->medications)));
        $this->member->medical_conditions_json = empty($this->member->conditions) ? '' : clean_page(implode(',', (array)json_decode($this->member->conditions)));

        $doctor_surgery = !empty($this->member->doctor_surgery) ?
            json_decode($this->member->doctor_surgery) :
            (object) [
                'manual_doctor_surgery' => 0,
                'id' => 0,
                'practice_name' => '',
                'city' => '',
                'address_1' => '',
                'address_2' => '',
                'postcode' => '',
                'phone' => '',
            ];


        return template('members/health_profile.twig', [
            'page_meta' => $page_meta,
            'member' => $this->member,
            'doctor_surgery' => $doctor_surgery,
            'all_medications' => json_encode(\Mtc\Shop\Medication::query()->pluck('name')->toArray()),
            'all_medical_conditions' => json_encode(\Mtc\Shop\MedicalCondition::query()->pluck('name')->toArray()),
            'self' => $_SERVER['REQUEST_URI']
        ]);
    }

    /**
     * Save account
     */
    public function healthProfileStore(Request $request)
    {
        $success = [];
        $errors = [];

        $this->member->setMedications( explode(',', $request->input('medications')) );
        $this->member->setConditions( explode(',', $request->input('conditions')) );
        $this->member->setAllergies( explode(',', $request->input('allergies')) );
        $this->member->doctor_surgery = json_encode( $request->input('doctor_surgery') );

        $this->member->save();

        if ($uploaded_proof = $request->file('exemption_proof')) {
            $proof_file_dir = NHSMember::get_exemption_proof_file_dir();
            $proof_file_name = uniqid() . '.' . $uploaded_proof->getClientOriginalExtension();
            $uploaded_proof->storeAs($proof_file_dir, $proof_file_name);
            $this->member->nhs_member->exemption_proof_file = $proof_file_name;
            $this->member->nhs_member->save();
        }

        $success['message'] = '<p class="success">We have successfully saved your health profile</p>';

        return json_encode([
            'errors' => $errors,
            'success' => $success,
        ]);
    }

    /**
     * Logs out member
     *
     * @return Factory|View
     */
    public function logout()
    {
        Auth::logout();

        $page_meta['title'] = config('app.name') . ' | Logout';

        return template('members/logout.twig', [
            'page_meta' => $page_meta,
            'member' => new Member(),
            'is_login_page' => true
        ]);
    }


    public function log_in_as_member(int $member_id)
    {
        $member = Member::findOrFail($member_id);

        $member->try_to_log_in();

        return redirect(route('members-dashboard', [], false));
    }


    public function referred_members(Request $request)
    {
        $page_meta['title'] = config('app.name') . ' | Patients';

        return template('members/referred_members.twig', [
            'member' => $this->member,
            'page_meta' => $page_meta,
            'current_page' => 'members-referred',
        ]);
    }



    public function get_prescription_data(Request $request)
    {
        if ($this->member->nhs_member->is_patient) {
            $prescriptions = $this->member->nhs_member->prescriptions();
        } else {
            $referred_prescriptions = $this->member->nhs_member->get_referred_prescriptions();
            $prescriptions = Prescription::query()->whereIn('id', $referred_prescriptions->pluck('id'));
        }

        $prescriptions = $prescriptions
            ->with('items')
            ->with('nhs_member.member')
            ->orderBy('updated_at', 'desc')
        ;

        if ($request->input('status')) {
            $prescriptions = $prescriptions->where('status', $request->input('status'));
        }

        $prescriptions = $prescriptions
            ->paginate($request->input('page_size', 0))
            ->appends($request->input())
        ;

        foreach($prescriptions as $prescription) {
            $prescription->status_label = Prescription::get_status_label($prescription->status);
            $prescription->member_display_id = $prescription->nhs_member->get_member_ref();
            $prescription->patient_full_name = $prescription->nhs_member->get_full_name();

            $prescription->is_editable = $prescription->is_editable();
            $prescription->prescription_edit_url = route('nhs-prescriptions-edit', [ $prescription->uuid ], false);

            $prescription->can_be_reordered = $prescription->can_be_reordered();
            $prescription->prescription_copy_url = route('nhs-prescriptions-copy', [ $prescription->uuid ], false);
        }

        return $prescriptions;
    }


    public function orders__nhs_prescriptions(Request $request)
    {
        $page_meta['title'] = config('app.name') . ' | NHS Prescriptions';

        $order_tabs = [
            'a' => [
                'label' => Prescription::get_status_label(Prescription::STATUS_DRAFT),
                'data' => [],
                'pagination' => true,
                'dataUrl' => route('members-orders-nhs-prescriptions-data', [
                    'status' => Prescription::STATUS_DRAFT,
                    'page_size' => 20,
                ]),
                'isActive' => true,
            ],
            'b' => [
                'label' => Prescription::get_status_label(Prescription::STATUS_PENDING),
                'data' => [],
                'pagination' => true,
                'dataUrl' => route('members-orders-nhs-prescriptions-data', [
                    'status' => Prescription::STATUS_PENDING,
                    'page_size' => 20,
                ]),
            ],
            'c' => [
                'label' => Prescription::get_status_label(Prescription::STATUS_COMPLETE),
                'data' => [],
                'pagination' => true,
                'dataUrl' => route('members-orders-nhs-prescriptions-data', [
                    'status' => Prescription::STATUS_COMPLETE,
                    'page_size' => 20,
                ]),
            ],
        ];

        return template('members/nhs_prescriptions/index.twig', [
            'page_meta' => $page_meta,
            'member_id'=> $this->member->id,
            'member' => $this->member,
            'tabs_config' => json_encode($order_tabs),
            'current_page' => 'members-orders-nhs-prescriptions',
        ]);
    }


    public function orders__subscriptions(Request $request)
    {
        $page_meta['title'] = config('app.name') . ' | Subscriptions';

        $subscriptions = Subscription::query()
            ->where('member_id', $this->member->id)
            ->get()
        ;

        foreach ($subscriptions as $sub) {
            $sub->append('edit_url');
            if (SubscriptionBundleType::isSubscriptionEditable($sub)) {
                $sub->edit_url = route('members-orders-subscription-edit', [ $sub->id ]);
            }
        }

        return template('members/subscriptions/index.twig', [
            'page_meta' => $page_meta,
            'subscriptions' => $subscriptions,
            'current_page' => 'members-orders-subscriptions',
            'active_nav_item' => 'subscriptions',
        ]);
    }


    public function orders__subscription_edit($subscription_id, Request $request)
    {
        $page_meta['title'] = config('app.name') . ' | Subscriptions';

        $sub = Subscription::findOrFail($subscription_id);

        $sub->authoriseAccessByCurrentUser();

        $sbt = SubscriptionBundleType::query()
            ->where('subscription_id', $sub->id)
            ->firstOrFail()
        ;

        if (! $sbt->bundleType->url) {
            abort(404);
        }

        $preselected = collect([]);
        foreach ($sub->items as $sub_item) {
            $preselected->push($sbt->bundleType->findByShopItemId(
                $sub_item->shop_item_id,
                $sub_item->shop_item_size_id
            ));
        }

        $query_params = [
            'force' => 1,
            'preselected_items' => $preselected->pluck('id')->toArray(),
            'submit_items_url' => route('members-orders-subscription', [ $subscription_id ], false),
            'submit_items_button_label' => 'Update subscription',
        ];

        $url = $sbt->bundletype->url . '?' . http_build_query($query_params);

        return redirect($url);
    }


    public function orders__subscription_update($subscription_id, Request $request)
    {
        $sub = Subscription::find($subscription_id);
        $sub->items()->delete();

        foreach ($request->input('item_ids') as $bti_id) {
            $bti = BundleTypeItem::find($bti_id);
            if ($bti) {
                $si = new SubscriptionItem();
                $si->shop_item_id       = $bti->shop_item_id;
                $si->shop_item_size_id  = $bti->shop_item_size_id;
                $si->subscription()->associate($sub);
                $si->save();
            }
        }

        return [
            'success' => true,
            'redirect_url' => route('members-orders-subscriptions'),
        ];
    }

    /**
     * View verification page
     *
     * @param Request $request
     * @return string
     */
    public function verify(Request $request): string
    {
        $page_meta['title'] = 'Verify your account';

        return template('members/verify.twig', [
            'page_meta' => $page_meta,
            'error' => session('error'),
            'name' => $this->member->addressBilling->firstname,
            'self' => $_SERVER['REQUEST_URI']
        ]);
    }

    /**
     * Sends verification code
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function sendVerificationCode(Request $request): JsonResponse
    {
        $errors = [];
        $messages = [];
        $send_to = $request->input('method') === 'email' ?
            $request->input('email') :
            $request->input('contact_no');
        try {
            $sent = App::make(MemberManager::class)->sendVerification(request()->input('method'), $send_to);
            if ($sent) {
                $device = request()->input('method') === 'email' ?
                    'email' :
                    'phone';
                $messages[] = "Please check your {$device} for verification code";
                // Update member's email address
                if ($device === 'email') {
                    $this->member->email = $request->input('email');
                    $this->member->save();
                }
            } else {
                $errors[] = 'Failed to send verification code. Please check your details and try again';
            }
        } catch (\Exception $exception) {
            $errors = [
                $exception->getMessage()
            ];
        }

        return response()->json([
            'messages' => $messages,
            'errors' => $errors,
        ]);
    }

    /**
     * Sends verification code
     *
     * @param Request $request
     * @return RedirectResponse
     */
    public function verifyCode(Request $request): RedirectResponse
    {
        $expiry = Carbon::createFromFormat('Y-m-d H:i:s', $this->member->verification_code_expiry);

        if ($request->input('code') !== $this->member->verification_code) {
            session()->flash('error', 'Verification code did not match');
            return redirect()->back();
        }

        if (Carbon::now() > $expiry) {
            session()->flash('error', 'Verification code has expired');
            return redirect()->back();
        }

        $this->member->verification_code = '';
        $this->member->account_verified = Carbon::now();
        $this->member->save();

        session()->flash('success', 'Your account has been verified');
        return redirect()->route('members-dashboard');
    }
}
