<?php

namespace App\Http\Controllers;

use App\Models\Answer;
use App\Models\OrganizationalUnit;
use App\Models\Question;
use App\Models\QuestionType;
use App\Models\UnitType;
use App\Models\User;
use Illuminate\Database\QueryException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class QuestionnaireController extends Controller
{
    public const SESSION_OFFICE_KEY = 'questionnaire_office_id';

    /**
     * List available questions.
     */
    public function index(Request $request): View|JsonResponse
    {
        $search = trim((string) $request->input('search', ''));

        $query = Question::query()
            ->with('questionType:id,name,slug')
            ->orderBy('sort')
            ->orderBy('id');

        if ($search !== '') {
            $query->where(function ($q) use ($search) {
                $q->where('question_text', 'like', '%' . $search . '%')
                    ->orWhereHas('questionType', function ($qt) use ($search) {
                        $qt->where('name', 'like', '%' . $search . '%')
                            ->orWhere('slug', 'like', '%' . $search . '%');
                    });

                if (ctype_digit($search)) {
                    $q->orWhere('id', (int) $search);
                }

                if (Schema::hasColumn('questions', 'sort') && ctype_digit($search)) {
                    $q->orWhere('sort', (int) $search);
                }
            });
        }

        if ($request->wantsJson()) {
            return response()->json($query->get());
        }

        $questions = $query->paginate(25)->withQueryString();

        return view('questions.index', compact('questions', 'search'));
    }

    /**
     * Show questionnaire form for the current user's organizational unit.
     * Questions already answered by the unit will not appear again.
     */
    public function form(Request $request): View
    {
        $user = $request->user();

        if ($user->organizational_unit_id) {
            $request->session()->forget(self::SESSION_OFFICE_KEY);
        }

        $unitId = (int) ($this->resolveQuestionnaireOfficeId($request) ?? 0);
        $targetUnit = null;
        if ($unitId > 0 && !$user->organizational_unit_id) {
            $targetUnit = OrganizationalUnit::query()
                ->where('id', $unitId)
                ->where('created_by', $user->id)
                ->first();
            if (!$targetUnit) {
                $request->session()->forget(self::SESSION_OFFICE_KEY);
                $unitId = 0;
            }
        }

        $needsUnitSetup = !$user->organizational_unit_id && $unitId === 0;
        $unitTypes = $needsUnitSetup ? UnitType::query()->orderBy('level')->orderBy('type_name')->get() : collect();
        $parentUnits = $needsUnitSetup ? OrganizationalUnit::query()->with('unitType')->orderBy('name')->get() : collect();

        if ($unitId === 0) {
            return view('questionnaire.form', [
                'questions' => collect(),
                'unitId' => null,
                'needsUnitSetup' => $needsUnitSetup,
                'usesSessionUnit' => false,
                'targetUnit' => $targetUnit,
                'unitTypes' => $unitTypes,
                'parentUnits' => $parentUnits,
            ]);
        }

        $questions = Question::query()
            ->with('questionType:id,name,slug')
            ->whereDoesntHave('answers', function ($q) use ($unitId) {
                $q->where('office_id', $unitId);
            })
            ->orderBy('sort')
            ->orderBy('id')
            ->get();

        return view('questionnaire.form', [
            'questions' => $questions,
            'unitId' => $unitId,
            'needsUnitSetup' => false,
            'usesSessionUnit' => !$user->organizational_unit_id,
            'targetUnit' => $targetUnit,
            'unitTypes' => collect(),
            'parentUnits' => collect(),
        ]);
    }

    /**
     * Create an organizational unit from the questionnaire flow (only if the user has no unit).
     */
    public function storeQuestionnaireUnit(Request $request)
    {
        $user = $request->user();
        if ($user->organizational_unit_id) {
            return redirect()
                ->route('questionnaire.form')
                ->withErrors(['unit' => __('لا يمكن إضافة وحدة من الاستبيان لأن حسابك مرتبط بوحدة تنظيمية.')]);
        }

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'parent_id' => ['nullable', 'exists:organizational_units,id'],
            'unit_type_id' => ['required', 'exists:unit_types,id'],
        ]);

        if (empty($validated['parent_id'])) {
            $validated['parent_id'] = null;
        }

        $validated['created_by'] = $user->id;
        $unit = OrganizationalUnit::create($validated);

        $request->session()->put(self::SESSION_OFFICE_KEY, $unit->id);

        return redirect()
            ->route('questionnaire.form')
            ->with('success', __('تم إنشاء الوحدة التنظيمية. يمكنك الآن تعبئة الاستبيان لهذه الوحدة.'));
    }

    /**
     * Clear the questionnaire-only organizational unit selection (session).
     */
    public function clearQuestionnaireUnit(Request $request)
    {
        if ($request->user()->organizational_unit_id) {
            return redirect()->route('questionnaire.form');
        }

        $request->session()->forget(self::SESSION_OFFICE_KEY);

        return redirect()
            ->route('questionnaire.form')
            ->with('success', __('تم إلغاء الوحدة المختارة. يمكنك إضافة وحدة جديدة.'));
    }

    /**
     * Create a new question.
     */
    public function storeQuestion(Request $request)
    {
        $validated = $request->validate([
            'question_text' => ['required', 'string'],
            'question_type_id' => ['required', 'exists:question_types,id'],
            'expected_safe_answer' => ['nullable', 'in:0,1'],
            'sort' => ['nullable', 'integer', 'min:1'],
        ]);

        $questionType = QuestionType::query()->findOrFail((int) $validated['question_type_id']);

        $payload = [
            'question_text' => $validated['question_text'],
            'question_type_id' => (int) $validated['question_type_id'],
            // keep legacy column in sync if still present
            'question_type' => Schema::hasColumn('questions', 'question_type') ? $questionType->slug : null,
            'expected_safe_answer' => isset($validated['expected_safe_answer'])
                ? (int) $validated['expected_safe_answer']
                : null,
        ];

        if (Schema::hasColumn('questions', 'sort')) {
            $nextSort = (int) (Question::query()->max('sort') ?? 0) + 1;
            $payload['sort'] = isset($validated['sort']) ? (int) $validated['sort'] : $nextSort;
        }

        $question = Question::create($payload);

        if ($request->wantsJson()) {
            return response()->json($question, 201);
        }

        return redirect()
            ->route('questions.index')
            ->with('success', 'تم إضافة السؤال بنجاح.');
    }

    /**
     * Show create question form (Blade).
     */
    public function createQuestionForm(): View
    {
        $questionTypes = QuestionType::query()
            ->orderBy('id')
            ->get(['id', 'name', 'slug']);

        return view('questions.create', compact('questionTypes'));
    }

    /**
     * Show edit question form.
     */
    public function editQuestion(Question $question): View
    {
        $questionTypes = QuestionType::query()
            ->orderBy('id')
            ->get(['id', 'name', 'slug']);

        return view('questions.edit', compact('question', 'questionTypes'));
    }

    /**
     * Update an existing question.
     */
    public function updateQuestion(Request $request, Question $question)
    {
        $rules = [
            'question_text' => ['required', 'string'],
            'question_type_id' => ['required', 'exists:question_types,id'],
            'expected_safe_answer' => ['nullable', 'in:0,1'],
        ];
        if (Schema::hasColumn('questions', 'sort')) {
            $rules['sort'] = ['required', 'integer', 'min:1'];
        }
        $validated = $request->validate($rules);

        $questionType = QuestionType::query()->findOrFail((int) $validated['question_type_id']);

        $payload = [
            'question_text' => $validated['question_text'],
            'question_type_id' => (int) $validated['question_type_id'],
            'question_type' => Schema::hasColumn('questions', 'question_type') ? $questionType->slug : null,
            'expected_safe_answer' => isset($validated['expected_safe_answer'])
                ? (int) $validated['expected_safe_answer']
                : null,
        ];
        if (Schema::hasColumn('questions', 'sort')) {
            $payload['sort'] = (int) $validated['sort'];
        }

        $question->update($payload);

        return redirect()
            ->route('questions.index')
            ->with('success', 'تم تعديل السؤال بنجاح.');
    }

    /**
     * Delete a question.
     */
    public function destroyQuestion(Question $question)
    {
        try {
            $question->delete();
            return redirect()
                ->route('questions.index')
                ->with('success', 'تم حذف السؤال بنجاح.');
        } catch (QueryException $e) {
            return redirect()
                ->route('questions.index')
                ->withErrors(['error' => 'لا يمكن حذف السؤال نظراً لوجود إجابات مرتبطة به.']);
        }
    }

    /**
     * Submit answers for the questionnaire form (one per question).
     */
    public function submit(Request $request)
    {
        $user = $request->user();
        $unitId = (int) ($this->resolveQuestionnaireOfficeId($request) ?? 0);

        if ($unitId === 0) {
            return redirect()
                ->back()
                ->withErrors(['organizational_unit_id' => __('يجب أن تكون مرتبطاً بوحدة تنظيمية، أو إنشاء وحدة من هذه الصفحة أولاً، ثم تعبئة الاستبيان.')]);
        }

        $validated = $request->validate([
            'answers' => ['required', 'array'],
            'answers.*.question_id' => ['required', 'exists:questions,id'],
            'answers.*.answer_value' => ['nullable', 'in:0,1'],
            'answers.*.notes' => ['nullable', 'string'],
        ]);

        $savedCount = $this->persistQuestionnaireAnswers($user, $unitId, $validated['answers']);

        if ($savedCount === 0) {
            return redirect()->back()->with('success', 'تم الحفظ: لم تقم بالإجابة على أي سؤال جديد.');
        }

        return redirect()->route('questionnaire.results')->with('success', "تم حفظ $savedCount إجابة بنجاح.");
    }

    /**
     * Submit questionnaire answers for a specific organizational unit (from unit show page).
     */
    public function submitForUnit(Request $request, OrganizationalUnit $organizationalUnit)
    {
        $user = $request->user();
        if (!$organizationalUnit->userCanSubmitQuestionnaire($user)) {
            abort(403);
        }

        $validated = $request->validate([
            'answers' => ['required', 'array'],
            'answers.*.question_id' => ['required', 'exists:questions,id'],
            'answers.*.answer_value' => ['nullable', 'in:0,1'],
            'answers.*.notes' => ['nullable', 'string'],
        ]);

        $unitId = (int) $organizationalUnit->id;
        $unansweredIds = Question::query()
            ->whereDoesntHave('answers', function ($q) use ($unitId) {
                $q->where('office_id', $unitId);
            })
            ->pluck('id')
            ->all();

        $filtered = array_values(array_filter($validated['answers'], function ($row) use ($unansweredIds) {
            return in_array((int) ($row['question_id'] ?? 0), $unansweredIds, true);
        }));

        $savedCount = $this->persistQuestionnaireAnswers($user, $unitId, $filtered);

        if ($savedCount === 0) {
            return redirect()
                ->route('organizational-units.show', $organizationalUnit)
                ->with('success', __('تم الحفظ: لم تُرسل إجابات جديدة، أو كانت الأسئلة مُجابة مسبقاً.'));
        }

        return redirect()
            ->route('organizational-units.show', $organizationalUnit)
            ->with('success', __('تم حفظ :count إجابة بنجاح.', ['count' => $savedCount]));
    }

    /**
     * @param  array<int, array<string, mixed>>  $answerRows
     */
    private function persistQuestionnaireAnswers(User $user, int $unitId, array $answerRows): int
    {
        $savedCount = 0;
        foreach ($answerRows as $row) {
            if (!isset($row['answer_value']) || $row['answer_value'] === null) {
                continue;
            }

            $question = Question::query()->findOrFail($row['question_id']);

            try {
                Answer::create([
                    'question_id' => $question->id,
                    'branch_id' => null,
                    'office_id' => $unitId,
                    'user_id' => (int) $user->id,
                    'answer_value' => $row['answer_value'],
                    'notes' => $row['notes'] ?? null,
                ]);
                $savedCount++;
            } catch (QueryException $e) {
                continue;
            }
        }

        return $savedCount;
    }

    /**
     * Show answers already submitted by the current user's organizational unit.
     */
    public function results(Request $request): View
    {
        $user = $request->user();
        $unitId = (int) ($this->resolveQuestionnaireOfficeId($request) ?? 0);

        if ($unitId === 0) {
            return view('questionnaire.results', [
                'unitId' => null,
                'rows' => collect(),
                'targetUnit' => null,
            ]);
        }

        $targetUnit = !$user->organizational_unit_id
            ? OrganizationalUnit::query()->where('id', $unitId)->where('created_by', $user->id)->first()
            : null;

        $rows = Answer::query()
            ->where('office_id', $unitId)
            ->join('questions', 'answers.question_id', '=', 'questions.id')
            ->leftJoin('question_types', 'questions.question_type_id', '=', 'question_types.id')
            ->select([
                'answers.id',
                'answers.answer_value',
                'answers.notes',
                'answers.created_at',
                'questions.question_text',
                'questions.sort as question_sort',
                DB::raw("COALESCE(question_types.slug, questions.question_type) as question_type_slug"),
            ])
            ->orderBy('questions.sort')
            ->orderBy('questions.id')
            ->orderBy('answers.created_at', 'desc')
            ->get();

        return view('questionnaire.results', [
            'unitId' => $unitId,
            'rows' => $rows,
            'targetUnit' => $targetUnit,
        ]);
    }

    /**
     * Submit an answer for a question.
     */
    public function storeAnswer(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'question_id' => ['required', 'exists:questions,id'],
            'branch_id' => ['nullable', 'exists:organizational_units,id'],
            'office_id' => ['nullable', 'exists:organizational_units,id'],
            'answer_value' => ['required', 'string'],
            'notes' => ['nullable', 'string'],
        ]);

        $question = Question::query()->findOrFail($validated['question_id']);
        $this->validateByQuestionType($this->resolveQuestionType($question), $validated['answer_value']);

        $answer = Answer::create([
            'question_id' => $question->id,
            'branch_id' => $validated['branch_id'] ?? null,
            'office_id' => $validated['office_id'] ?? null,
            'user_id' => (int) $request->user()->id,
            'answer_value' => $validated['answer_value'],
            'notes' => $validated['notes'] ?? null,
        ]);

        return response()->json($answer, 201);
    }

    /**
     * List answers for one question.
     */
    public function questionAnswers(Question $question): JsonResponse
    {
        $answers = $question->answers()
            ->with(['user:id,name,email', 'branch:id,name', 'office:id,name'])
            ->latest('created_at')
            ->get();

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

    private function validateByQuestionType(string $type, string $value): void
    {
        if ($type === 'yes_no' && !in_array(strtolower($value), ['yes', 'no', '1', '0'], true)) {
            abort(422, 'answer_value for yes_no must be yes/no or 1/0.');
        }

        if ($type === 'number' && !is_numeric($value)) {
            abort(422, 'answer_value for number must be numeric.');
        }
    }

    private function resolveQuestionType(Question $question): string
    {
        if ($question->relationLoaded('questionType') && $question->questionType) {
            return $question->questionType->slug;
        }

        if ($question->questionType) {
            return $question->questionType->slug;
        }

        return (string) $question->question_type;
    }

    /**
     * Office (organizational unit) used for questionnaire answers: user's unit, or session unit if user has none.
     */
    private function resolveQuestionnaireOfficeId(Request $request): ?int
    {
        $user = $request->user();
        if ($user->organizational_unit_id) {
            return (int) $user->organizational_unit_id;
        }

        $sid = (int) ($request->session()->get(self::SESSION_OFFICE_KEY) ?? 0);
        if ($sid <= 0) {
            return null;
        }

        $exists = OrganizationalUnit::query()
            ->where('id', $sid)
            ->where('created_by', $user->id)
            ->exists();

        if (!$exists) {
            $request->session()->forget(self::SESSION_OFFICE_KEY);

            return null;
        }

        return $sid;
    }
}
