<?php

namespace App\Http\Controllers;

use App\Events\AssessmentCreatedEvent;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Plugins\Clinic\Src\Models\Review;
use Mtc\Shop\Assessment\Answer;
use Mtc\Shop\Assessment\Assessment;
use Mtc\Shop\Assessment\Form;
use Mtc\Shop\Assessment\Question;


class AssessmentCheckoutController extends Controller
{
    private $form;
    private $errors = [];
    private $member;
    private $question_errors = [];
    private $category_id = null;



    /*** Entry Points ***/

    public function save($form_id, Request $request)
    {
        $this->member = Auth::getLoggedInMember();

        $this->form = Form::query()
            ->findOrFail($form_id);

        // Only apply rate limiting to final assessment submissions, not intermediate saves
        $isComplete = $request->input('complete') === '1';

        if ($isComplete) {
            // If rate limit is met, send a 429 to the view
            $rateLimit = \Mtc\Core\RateLimit::log('assessment_post', 'Sorry, you have made too many requests from your IP address. Please try again in a minute.', 10);

            if($rateLimit && $rateLimit['limited']) {
                return response()->json([
                    'ok' => false,
                    'rate_limited' => true,
                    'message' => $rateLimit['message'],
                    'retry_after' => 60,
                ], 429);
            }
        }

        $saved = [];

        if (!empty($request->input('category_id'))) {
            $this->category_id = $request->input('category_id');
        }

        if (!empty($request->input('product_id'))) {
            $this->product_id = $request->input('product_id');
        }

        $temp_assessment = $this->save_assessment($request);
        if ($temp_assessment) {
            $saved[] = [
                'id' => $temp_assessment->id,
            ];
        }

        if (!empty($this->question_errors)) {
            Log::debug('Error submitting assessment form: ' . $this->form->name . ' (ID: ' . $form_id . ')');
            Log::debug(print_r($this->question_errors, true));
        }

        $redirect = session()->has(Assessment::ASSESSMENT_COMPLETE_REDIRECT) ?
            session(Assessment::ASSESSMENT_COMPLETE_REDIRECT) :
            '';

        $data = [
            'ok' => empty($this->errors),
            'errors' => $this->errors,
            'question_errors' => $this->question_errors,
            'questions' => $request['questions'],
            'change_count' => $request['change_count'],
            'created_assessments' => $saved,
            'redirect' => $redirect,
        ];

        return response()->json($data);
    }





    /*** Helpers ***/

    private function getDOBForUser(string $user_name, Request $request)
    {
        $dob = null;

        $request_users = $request->input('users', []);
        foreach ($request_users as $request_user) {
            if ($request_user['name'] == $user_name) {
                $dob = $request_user['dob'];
                break;
            }
        }

        if ($dob) {
            $dob = Carbon::createFromFormat('d/m/Y', $dob)->format('c');
        }

        return $dob;
    }

    /**
     * Saves assessment
     *
     * @param Request $request
     * @return Assessment|null
     */
    private function save_assessment(Request $request): ?Assessment
    {
        $questions = $request->input('questions', []);

        $allowed_doctor_surgery_keys = [
            'manual_doctor_surgery',
            'id',
            'practice_name',
            'ods_code',
            'address_1',
            'address_2',
            'address_3',
            'city',
            'postcode',
            'phone',
            'notify',
        ];

        $doctor_surgery = [];
        $raw_doctor_surgery = array_intersect_key(
            (array) $request->input('doctor_surgery', []),
            array_flip($allowed_doctor_surgery_keys)
        );
        foreach ($raw_doctor_surgery as $key => $value) {
            if (!is_scalar($value) && $value !== null) {
                continue;
            }
            $doctor_surgery[$key] = is_string($value) ? trim(strip_tags($value)) : $value;
        }

        if (!empty($request->input('complete'))) {
            // Validate only when submitting a completed assessment.
            // bypass_validation[] is client-supplied; only trust IDs that have
            // an existing stored file answer for this member+form.
            $bypass_validation = $this->resolveTrustedBypassIds(
                $request->input('bypass_validation', [])
            );
            $errors = $this->form->validate($questions, request()->file('questions'), $bypass_validation);

            if (!empty($errors)) {
                $this->set_error('We are unable to offer you any medication based on your answers');
                $this->question_errors = array_merge($this->question_errors, $errors);

                return null;
            }
        } else {
            // When submitting incomplete assessment form, we don't save it if the member is not logged in
            if (empty($this->member->id)) {
                return null;
            }
        }

        if (!empty($this->member->id)) {
            // If the member has logged in, remove incomplete assessments for this form
            Assessment::query()
                ->with('answers')
                ->where('form_id', $this->form->id)
                ->where('member_id', $this->member->id)
                ->where('is_completed', '0')
                ->get()
                ->each(function (Assessment $assessment) {
                    $assessment->answers()->delete();
                    $assessment->delete();
                });
        }

        /** @var Assessment $assessment */
        $assessment = Assessment::query()
            ->create([
                'member_id'       => $this->member->id ?? 0,
                'form_id'         => $this->form->id,
                'item_id'         => 0,
                'is_completed'    => $request->input('complete'),
            ]);

        if (!empty($questions)) {

            foreach ($questions as $question_id => $answer) {

                $question = (new Question())->find($question_id);
                $changes = (int)$request->input('change_count.' . $question_id);


                if ($question->question_type === 'notify_gp') {

                    $doctor_surgery['notify'] = $answer;
                    $answer_to_save           = json_encode($doctor_surgery);

                    // Update doctor surgery on member profile
                    $this->member->doctor_surgery                 = $answer_to_save;
                    $_SESSION['health_profile']['doctor_surgery'] = $answer_to_save;
                } elseif (in_array($question->question_type, [
                    Question::TYPE_BMI,
                    Question::TYPE_BP_READINGS,
                ])) {
                    $answer_to_save = json_encode($answer);
                } else {
                    $answer_to_save = $question->is_multiple ? json_encode($answer) : $answer;
                }

                $confirmed = request()->input('answer_confirmed.'
                    . $question_id);

                if (!empty($confirmed) && $confirmed == 'true') {
                    $confirmed = 1;
                } else {
                    $confirmed = 0;
                }


                $assessment->answers()
                    ->create([
                        'form_id'                           => $this->form->id,
                        'question_id'                       => $question_id,
                        'answer'                            => $answer_to_save,
                        'answer_change_count'               => $changes,
                        'answer_confirmed'                  => $confirmed,
                        'answer_changed_after_confirmation' => request()->input('answer_changed_after_confirmation.'
                            . $question_id, 0)
                    ])
                ;

                if ($question->question_type === 'allergies') {

                    if (!empty($this->member->id)) {
                        $this->member->setAllergies(explode(',', $answer));
                    } else {
                        $_SESSION['health_profile']['allergies'] = explode(',', $answer);
                    }

                } elseif ($question->question_type === 'medications') {
                    if (!empty($this->member->id)) {
                        $this->member->setMedications(explode(',', $answer));
                    } else {
                        $_SESSION['health_profile']['medications'] = explode(',', $answer);
                    }

                } elseif ($question->question_type === 'conditions') {
                    if (!empty($this->member->id)) {
                        $this->member->setConditions(explode(',', $answer));
                    } else {
                        $_SESSION['health_profile']['conditions'] = explode(',', $answer);
                    }
                }
            }
            // Save health profile
            if (!empty($this->member->id)) {
                $this->member->save();
            }
        }


        foreach ($request->file('questions', []) as $question_id => $uploaded_file) {

            $answer   = Str::random()
                . '.'
                . $uploaded_file->getClientOriginalExtension();
            $uploaded_file->storeAs(Assessment::UPLOAD_PATH, $answer);


            $assessment->answers()
                ->create([
                    'form_id'     => $this->form->id,
                    'question_id' => $question_id,
                    'answer'      => $answer,
                ])
            ;
        }

        if ($request->input('complete')) {
            // Save health profile
            if (!empty($this->member->id)) {
                $this->member->save();
            }

            if (!empty($this->product_id)) {
                $_SESSION['assessments'][$this->product_id] = $assessment->id;
            }

            if (!empty($this->category_id)) {
                $_SESSION['category_assessments'][$this->category_id] = $assessment->id;
            }

            $assessment->setAsLatest();

            Event::dispatch(AssessmentCreatedEvent::class, new AssessmentCreatedEvent($assessment, $request));
        }

        return $assessment;
    }


    private function set_error($msg) {
        $this->errors[] = $msg;
    }

    /**
     * Intersect client-supplied bypass_validation IDs with file-type question
     * IDs that actually have a stored non-empty answer for this member+form.
     * Prevents a caller from skipping required/format checks on questions
     * they have never answered.
     */
    private function resolveTrustedBypassIds($raw_ids): array
    {
        $requested = array_filter(array_map('intval', (array) $raw_ids));
        if (empty($requested) || empty($this->member->id ?? null)) {
            return [];
        }

        $assessment_ids = Assessment::query()
            ->where('form_id', $this->form->id)
            ->where('member_id', $this->member->id)
            ->pluck('id');

        if ($assessment_ids->isEmpty()) {
            return [];
        }

        $file_question_ids = Question::query()
            ->whereIn('id', $requested)
            ->whereIn('question_type', Question::$file_question_types)
            ->pluck('id');

        if ($file_question_ids->isEmpty()) {
            return [];
        }

        return Answer::query()
            ->whereIn('assessment_id', $assessment_ids)
            ->whereIn('question_id', $file_question_ids)
            ->whereNotNull('answer')
            ->where('answer', '!=', '')
            ->pluck('question_id')
            ->unique()
            ->values()
            ->all();
    }

}
