<?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\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) { continue; }

$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', []);

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

            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(static function (Assessment $assessment): void {
                    $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(',', (string) $answer));
                    } else {
                        $_SESSION['health_profile']['allergies'] = explode(',', (string) $answer);
                    }
                } elseif ($question->question_type === 'medications') {
                    if (! empty($this->member->id)) {
                        $this->member->setMedications(explode(',', (string) $answer));
                    } else {
                        $_SESSION['health_profile']['medications'] = explode(',', (string) $answer);
                    }
                } elseif ($question->question_type === 'conditions') {
                    if (! empty($this->member->id)) {
                        $this->member->setConditions(explode(',', (string) $answer));
                    } else {
                        $_SESSION['health_profile']['conditions'] = explode(',', (string) $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;
    }
}
