<?php

namespace Mtc\Shop\Assessment;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\hasMany;
use Mtc\Cms\Models\AssetGalleryIcon;
use Mtc\Modules\Members\Models\Member;
use Mtc\Shop\Category;
use Mtc\Shop\Item;

/**
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 *
 * Accessors
 *
 * @property Collection $questions
 *
 */
class Form extends Model
{
    protected $table = 'assessment_forms';

    protected $fillable = [
        'name',
        'is_active',
        'icon_id',
    ];

    /**
     * Define the relationship to Item
     * @return hasMany
     */
    public function items(): hasMany
    {
        return $this->hasMany(Item::class, 'form_id');
    }

    /**
     * Define the relationship to Category
     * @return hasMany
     */
    public function categories(): hasMany
    {
        return $this->hasMany(Category::class, 'form_id');
    }

    /**
     * Define the relationship to Questions
     * @return hasMany
     */
    public function questions(): hasMany
    {
        return $this->hasMany(Question::class, 'form_id');
    }

    /**
     * Define the relationship to Answers
     * @return hasMany
     */
    public function answers(): hasMany
    {
        return $this->hasMany(Answer::class, 'form_id');
    }

    /**
     * @param Builder $query Query builder object
     * @return Builder
     *
     */

    public function scopeActive(Builder $query): Builder
    {
        return $query->where('is_active', 1);
    }

    /**
     * Define the relationship to Assessments
     * @return hasMany
     */
    public function assessments(): hasMany
    {
        return $this->hasMany(Assessment::class, 'form_id');
    }

    public function icon(): BelongsTo
    {
        return $this->belongsTo(AssetGalleryIcon::class, 'icon_id');
    }

    /**
     * @param $answers
     * @param $files
     * @return array
     */
    public function validate($answers, $files, $bypass = [])
    {
        $errors = [];
        $questions = $this->questions()
            ->active()
            ->orderBy('id')
            ->get();

        // Validate questions
        foreach ($questions as $question) {
            if (! in_array($question->id, $bypass)) {
                if ($this->failsRequiredAndMissing($question, $answers, $files)) {
                    $errors['questions'][$question->id] = 'This field is required';
                }

                if (
                    $question->expectsFile()
                    && ! empty($files[$question->id])
                    && $question->isValidFileFormat($files[$question->id]) === false
                ) {
                    $errors['questions'][$question->id] = 'This file type is not supported';
                }

                if ($answers && ! empty($question->cant_proceed_if)) {
                    $blocker_answers = (array) json_decode($question->cant_proceed_if);
                    foreach ($blocker_answers as $blocker_answer) {
                        if (isset($answers[$question->id]) && $answers[$question->id] === $blocker_answer) {
                            $errors['questions'][$question->id] = 'Purchase is not allowed.';
                        }
                    }
                }
            }
        }

        return $errors;
    }

    /**
     * @param $question
     * @param $answers
     * @param $files
     * @return bool
     */
    protected function failsRequiredAndMissing($question, $answers, $files): bool
    {
        // If it's not required, then valid
        if (! $question->is_required) {
            return false;
        }
        // If question type needs skiped validation, then valid
        if (in_array($question->question_type, ['html', 'section'], true)) {
            return false;
        }

        $missing_field = $question->expectsFile() ? empty($files[$question->id]) : empty($answers[$question->id]);

        // If the field has value, then valid
        if (! $missing_field) {
            return false;
        }

        // Has no conditional show, is empty and required, then invalid
        if (empty($question->show_if_question)) {
            return true;
        }

        // Has conditional show, but it's multi-level conditions and the conditional question has no answer, then valid
        if (empty($answers[$question->show_if_question])) {
            return false;
        }

        // Has conditional show and condition matches, then invalid
        return $question->show_if_answer === $answers[$question->show_if_question];
    }

    /**
     * Clones form from the parent. Adds all questions and sets the new name
     *
     * @param $new_name
     * @return mixed
     */
    public function cloneForm($new_name)
    {
        $form = $this->create([
            'name' => $new_name,
            'is_active' => '1',
        ]);

        $question_id_map = [];

        foreach ($this->questions as $question) {
            $new_question = new Question;
            $new_question->fill($question->toArray());
            $new_question->form_id = $form->id;
            $new_question->save();
            $question_id_map[$question->id] = $new_question->id;
        }

        // Once we have created all new questions, we can remap the conditional questions
        foreach ($question_id_map as $old_question_id => $new_question_id) {
            $new_question = (new Question)->find($new_question_id);
            // If we have the conditional question we need to find the corresponding new question
            if ($new_question->show_if_question > 0) {
                // Find old question
                $old_question = (new Question)->find($old_question_id);
                // Find which new question is the conditional question by using id map
                $new_question->show_if_question = $question_id_map[$old_question->show_if_question];
                $new_question->save();
            }
        }

        return $form->id;
    }

    /**
     * Gets last member assessment
     *
     * @param Member|null $member
     * @return Model|HasMany|object|null
     */
    public function getMemberAssessment(?Member $member = null)
    {
        return $this->assessments()
            ->where('member_id', $member->id)
            ->orderBy('id', 'desc')
            ->first();
    }

    public function getActiveQuestions()
    {
        return $this->questions()
            ->active()
            ->orderBy('sort')
            ->get();
    }

    public function getQuestionsEnsuringOneQuestionPerSection()
    {
        $questions = collect([]);

        $temp_questions = $this->getActiveQuestions();

        $section_template = new Question;
        $section_template->question_type = 'section';
        $section_template->question_text = 'Assessment Form';
        $section_template->is_active = true;

        foreach ($temp_questions as $key => $temp_question) {
            if ($temp_question->question_type == 'section')
                continue;

            $temp_section = clone $section_template;
            $temp_section->id = $key;
            $questions->push($temp_section);
            $questions->push($temp_question);
        }

        return $questions;
    }
}
