<?php

namespace Mtc\Plugins\NHS\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Modules\Members\Classes\MemberManager;
use Mtc\Modules\Members\Models\Member;
use Mtc\Plugins\NHS\Classes\NHS;
use Mtc\Plugins\NHS\Classes\NHSMember;
use Mtc\Plugins\NHS\Classes\Prescription;


class PrescriptionsController extends BaseController
{

    private $logged_in_member = null;


    public function __construct()
    {
        $this->logged_in_member = Auth::getLoggedInMember();

        // This is to allow referrers to log in as their patients, but then
        // swith back to their account when they work with prescriptions.
        if ($this->logged_in_member->id) {
            if (! $this->logged_in_member->can_manage_own_account()) {
                $referrer = Member::findOrFail($this->logged_in_member->referrer->id);
                $referrer->try_to_log_in();
                $this->logged_in_member = Auth::getLoggedInMember();
            }
        }
    }


    /* MAIN */


    public function welcome()
    {
        if ($this->logged_in_member->id) {
            return redirect()->route('nhs-prescriptions-create');
            exit;
        }

        return template('NHS/pages/referrer_question.twig', []);
    }


    public function create()
    {
        $prescription = Prescription::create($this->logged_in_member);

        return redirect()->route('nhs-prescriptions-edit', [
            'prescription_uuid' => $prescription->uuid,
        ]);
    }


    public function edit($uuid)
    {
        $prescription = Prescription::get_by_uuid($uuid);

        $prescription->authorise_access_by($this->logged_in_member);

        $logged_in_member_data = [
            'id' => null,
            'email' => null,
            'is_referrer' => null,
            'referred_members' => [],
            'is_patient_email_visible' => true,
            'is_patient_phone_number_visible' => true,
        ];

        if ($this->logged_in_member->id) {
            $logged_in_member_data = [
                'id' => $this->logged_in_member->id,
                'email' => $this->logged_in_member->email,
                'is_referrer' => $this->logged_in_member->nhs_member->is_referrer(),
                'referred_members' => $this->logged_in_member->referred_members,
                'is_activated' => $this->logged_in_member->is_activated,
                'is_patient_email_visible' => (! $this->logged_in_member->nhs_member->is_care_home_staff()),
                'is_patient_phone_number_visible' => (! $this->logged_in_member->nhs_member->is_care_home_staff()),
            ];
        }

        $prescription->status_label = Prescription::get_status_label($prescription->status);

        return template('NHS/pages/prescription_edit.twig', [
            'prescription' => $prescription,
            'logged_in_member' => $logged_in_member_data,
        ]);
    }


    public function copy($uuid)
    {
        $prescription = Prescription::get_by_uuid($uuid);

        $prescription->authorise_access_by($this->logged_in_member);

        $new_prescription = $prescription->replicate();
        $new_prescription->uuid = (string)Str::uuid();
        $new_prescription->copy_of_prescription_id = $prescription->id;
        $new_prescription->status = Prescription::STATUS_DRAFT;
        $new_prescription->save();

        foreach ($prescription->items as $item) {
            $new_item = $item->replicate();
            $new_prescription->items()->save($new_item);
        }

        return redirect()->route('nhs-prescriptions-edit', [
            'prescription_uuid' => $new_prescription->uuid,
        ]);
    }


    private function generate_dummy_data_for_care_home_patients(Request $request, Prescription $prescription)
    {
        if ($this->logged_in_member->id && $this->logged_in_member->nhs_member->is_care_home_staff()) {
            if (! $request->input('formdata.member.email')) {
                $formdata = $request->input('formdata');
                Arr::set($formdata, 'member.email', $prescription->get_dummy_email_address());
                $request->merge(['formdata' => $formdata]);
            }
        }
    }


    public function save($uuid, Request $request)
    {
        $result = [
            'errors' => [],
        ];

        $prescription = Prescription::get_by_uuid($uuid);
        $prescription->authorise_access_by($this->logged_in_member);

        if ($request->input('formdata.prescription_items')) {
            if ($output = $this->save_prescription_items($prescription, $request)) {
                $result['errors']['prescription_items'] = $output;
            }
        } else {
            $result['errors']['prescription_items_error'] = 'You have to add at least one item.';
        }

        $this->generate_dummy_data_for_care_home_patients($request, $prescription);

        if ($request->input('formdata.member.email') || $request->input('formdata.member.contact_no')) {
            if ($output = $this->save_member_details($prescription, $request)) {
                $result['errors'] += $output;
            }
        } else {
            $result['errors']['email'] = 'You have to provide an email or phone number.';
            $result['errors']['contact_no'] = 'You have to provide an email or phone number.';
        }

        if (! $result['errors']) {
            $prescription->save_status(Prescription::STATUS_PENDING);
        }

        return $result;

    }



    /* HELPERS */


    private function save_member_password(Member $patient, Request $request)
    {
        $errors = [];

        if ($patient->is_activated) {
            return $errors;
        }

        if ($request->input('formdata.member.password')) {
            $patient->password = $request->input('formdata.member.password');
            $patient->is_activated = 1;
            $patient->save();
        } else {
            $errors['password'] = 'Password is required.';
        }

        return $errors;
    }


    private function create_new_patient_from_input(array $data)
    {
        $output = [
            'patient' => null,
            'errors' => [],
        ];

        $allow_no_email = false;
        if ($this->logged_in_member->id && $this->logged_in_member->nhs_member->is_referrer()) {
            $allow_no_email = true;
        }

        $member_manager = new MemberManager();
        if ($patient = $member_manager->save($data, new Member(), [
            MemberManager::PARAM_ALLOW_NO_EMAIL => $allow_no_email,
        ])) {

            $patient->nhs_member->set_type(NHSMember::TYPE_PATIENT);

            // Add referrer...
            if ($this->logged_in_member->id && $this->logged_in_member->nhs_member->is_referrer()) {
                $patient->referrer()->associate($this->logged_in_member);
                $patient->save();
            } else { // or log in if self-referred.
                Auth::login($patient);
            }

            $output['patient'] = $patient;

        } else {
            $output['errors'] = $member_manager->getErrors();
        }

        return $output;
    }


    private function save_prescription_items(Prescription $prescription, Request $request)
    {
        $output = null;

        $input_data = (array)$request->input('formdata.prescription_items');
        $processed_items = $prescription->save_items_from_input($input_data);

        if ($processed_items) {
            foreach ($processed_items as $processed_item) {
                if ($processed_item->errors) {
                    $output = $processed_items; // All or nothing.
                    break;
                }
            }
        }

        return $output;
    }


    private function save_member_addresses(Member $patient, Request $request)
    {
        $errors = [];

        $address_billing = $request->input('formdata.member_addresses.billing');

        $address_shipping = $request->input('formdata.member_addresses.shipping');
        if ($request->input('formdata.prescription.shipping_same_as_billing')) {
            $address_shipping = $address_billing;
            $address_shipping['type'] = 'shipping';
        }

        $patient->fresh();
        $patient->load('addressBilling');
        $patient->load('addressShipping');

        if ($output = $patient->addressBilling->save_from_input($address_billing)) {
            $errors['address_billing'] = [] + $output;
        }

        if ($output = $patient->addressShipping->save_from_input($address_shipping)) {
            $errors['address_shipping'] = [] + $output;
        }

        return $errors;
    }


    private function check_email_can_be_used(Member $patient)
    {
        $errors = [];

        if (! $this->logged_in_member->id) {

            $errors['email'] = 'A member with this email address already exists. Please update or log in.';

        } else {

            if ($this->logged_in_member->nhs_member->is_patient) {

                if ($patient->id != $this->logged_in_member->id) {
                    $errors['email'] = "Email can't be changed.";
                }

            } else {

                if ($patient->referrer->id != $this->logged_in_member->id) {
                    $errors['email'] = 'A patient with this email address already exists. Please update or log in.';
                }

            }

        }

        return $errors;
    }


    private function check_phone_can_be_used(Member $patient)
    {
        $errors = [];

        if (! $this->logged_in_member->id) {

            $errors['contact_no'] = 'A member with this contact number already exists. Please update or log in.';

        } else {

            if ($this->logged_in_member->nhs_member->is_patient) {

                if ($patient->id != $this->logged_in_member->id) {
                    $errors['contact_no'] = "Contact number can't be changed. {$patient->id} {$this->logged_in_member->id}";
                }

            } else {

                if ($patient->referrer->id != $this->logged_in_member->id) {
                    $errors['contact_no'] = 'A patient with this contact number already exists. Please update or log in.';
                }

            }

        }

        return $errors;
    }


    private function save_consent_data(Member $patient, Request $request)
    {
        $errors = [];

        if ($request->input('formdata.member.has_nominated_client_as_pharmacy_of_choice')) {
            $patient->has_nominated_client_as_pharmacy_of_choice = true;
        } else {
            $patient->has_nominated_client_as_pharmacy_of_choice = null;
        }

        if ($request->input('formdata.member.has_confirmed_terms')) {
            $patient->confirmed_terms_at = date('Y-m-d H:i:s');
        } else {
            $patient->confirmed_terms_at = null;
        }


        $errors_bag = $patient->validate()->errors();
        $errors = \App\FlashMessage::getImplodedMessages($errors_bag);
        if (! $errors) {
            $patient->save();
        }

        return $errors;
    }


    private function save_member_details(Prescription $prescription, Request $request)
    {
        $errors = [];

        $nhs_member_data = $request->input('formdata.nhs_member');
        $member_data = $request->input('formdata.member');


        if ($prescription->nhs_member) {
            $patient = $prescription->nhs_member->member;
        }

        if (! $patient) {
            $patient = Member::where('id', $member_data['id'])->first();
        }

        if (! $patient && $member_data['email']) {
            $patient = Member::where('email', $member_data['email'])->first();
            if ($patient) {
                $errors += $this->check_email_can_be_used($patient);
            }
        }

        if ($errors) {
            return $errors;
        }


        $is_new_patient = false;

        if (! $patient) { // Create a new member (of type patient);
            $is_new_patient = true;

            $input_data = [
                'billing_firstname' => $nhs_member_data['firstname'],
                'billing_lastname' => $nhs_member_data['lastname'],
                'email' => $member_data['email'],
                'contact_no' => $member_data['contact_no'],
                'no_password' => true,
            ];
            $output = $this->create_new_patient_from_input($input_data);
            if ($output['errors']) {
                $errors += $output['errors'];
                foreach ($errors as $key => $value) {
                    if (in_array($key, ['billing_firstname', 'billing_lastname'])) {
                        $errors[str_replace('billing_', '', $key)] = $value;
                    }
                }
            } else {
                $patient = $output['patient'];
            }
        }

        if ($patient) {
            $errors += $this->save_consent_data($patient, $request);

            $errors += $this->save_member_addresses($patient, $request);
            $errors += $patient->nhs_member->save_from_input($nhs_member_data);

            if (! $patient->referrer) { // Request password from self-referred only.
                $errors += $this->save_member_password($patient, $request);
            }

            $prescription->nhs_member()->associate($patient->nhs_member);
            $prescription->save();

        } else {
            $errors['email'] or ($errors['email'] = "Couldn't find or create member.");
        }

        return $errors;
    }

}
