<?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\Facades\Validator;
use Illuminate\Support\Str;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Plugins\Clinic\Src\Models\Review;
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)
    {
        $validator = Validator::make(
            array_merge($request->all(), ['form_id' => $form_id]),
            [
                'form_id' => 'required|integer|exists:assessment_forms,id',
                'questions' => 'sometimes|array',
                'complete' => 'sometimes|in:0,1',
                'category_id' => 'sometimes|nullable|integer',
                'product_id' => 'sometimes|nullable|integer',
            ]
        );

        if ($validator->fails()) {
            if ($request->expectsJson() || $request->ajax()) {
                return response()->json([
                    'error' => 'Validation failed',
                    'errors' => $validator->errors(),
                ], 422);
            }

            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        $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 = '';
        if ($request->input('complete')) {
            $redirect = session()->pull(Assessment::ASSESSMENT_COMPLETE_REDIRECT, '');
            if (empty($redirect) && session()->has('reorder_assessment_queue')) {
                $redirect = route('reorder-assessment-next', [], false);
            }
        }

        $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', []);
        $doctor_surgery = $request->input("doctor_surgery", []);

        // IDs of image questions whose existing file should be kept (frontend confirms file_already_set)
        $bypassIds = array_filter(array_map('intval', $request->input('bypass_validation', [])));

        if (!empty($request->input('complete'))) {
            // Validate only when submitting a completed assessment
            $errors = $this->form->validate($questions, request()->file('questions'), $bypassIds);

            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;
            }
        }

        $isComplete = !empty($request->input('complete'));

        if ($isComplete && !empty($this->member->id)) {
            // On final submission, clean up any remaining drafts for this member+form
            $draftIds = Assessment::query()
                ->where('form_id', $this->form->id)
                ->where('member_id', $this->member->id)
                ->where('is_completed', '0')
                ->pluck('id');
            if ($draftIds->isNotEmpty()) {
                \Mtc\Shop\Assessment\Answer::whereIn('assessment_id', $draftIds)->delete();
                Assessment::whereIn('id', $draftIds)->delete();
            }
        }

        $assessment = null;

        $preservedImageQuestionIds = [];

        if (!$isComplete && !empty($this->member->id)) {
            // For draft saves, try to reuse an existing non-expired draft
            $assessment = Assessment::getDraftForMember($this->member, $this->form->id);
            if ($assessment) {
                // Preserve existing image answers where no new file was uploaded
                // and the frontend still has the file set (bypass_validation includes the ID)
                $newFileIds = array_map('intval', array_keys($request->file('questions', [])));
                $preservedImageQuestionIds = $assessment->answers()
                    ->whereHas('question', function ($q) {
                        $q->whereIn('question_type', Question::$file_question_types);
                    })
                    ->whereNotIn('question_id', $newFileIds)
                    ->whereIn('question_id', $bypassIds)
                    ->pluck('question_id')
                    ->toArray();

                // Delete all answers except preserved image answers
                $deleteQuery = $assessment->answers();
                if (!empty($preservedImageQuestionIds)) {
                    $deleteQuery->whereNotIn('question_id', $preservedImageQuestionIds);
                }
                $deleteQuery->delete();

                $assessment->touch();
            }
        }

        if (!$assessment) {
            /** @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) {

                // Skip image questions whose answers were preserved from the previous draft save
                if (in_array((int) $question_id, $preservedImageQuestionIds)) {
                    continue;
                }

                $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;
            }

            // Store assessment by form ID for later retrieval
            $_SESSION['form_assessments'][$this->form->id] = $assessment->id;

            $assessment->setAsLatest();

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

        return $assessment;
    }


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

}
