<?php

namespace App\Http\Controllers;

use App\Models\Test;
use App\Models\TestAttempt;
use App\Models\Answer;
use App\Models\Option;
use App\Models\Formula;
use App\Models\FormulaResult;
use App\Calculators\FormulaCalculator;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;

class TestTakingController extends Controller
{
    protected $calculator;

    public function __construct(FormulaCalculator $calculator)
    {
        $this->calculator = $calculator;
    }

    /**
     * ثبت نهایی پاسخ‌های کاربر + محاسبه فرمول‌ها با پشتیبانی از فرمول در فرمول
     */
    public function submit(Request $request, Test $test): JsonResponse
    {
        $validated = $request->validate([
            'participant_name' => 'required|string|max:255',
            'participant_phone' => 'required|string|max:20',
            'answers' => 'required|array|min:1',
            'answers.*.question_id' => 'required|integer|exists:questions,id',
            'answers.*.option_id' => 'nullable|integer|exists:options,id',
            'answers.*.text_answer' => 'nullable|string|max:1000',
        ]);

        return DB::transaction(function () use ($request, $test, $validated) {

            $attempt = TestAttempt::create([
                'user_id' => 1,
                'test_id' => $test->id,
                'participant_name' => $validated['participant_name'],
                'participant_phone' => $validated['participant_phone'],
                'status' => 'completed',
                'total_score' => 0,
                'completed_at' => now(),
            ]);

            $answersData = [];
            $totalScore = 0;
            $answersMap = collect($validated['answers'])->keyBy('question_id');

            $optionIds = collect($validated['answers'])->pluck('option_id')->filter()->unique();
            $options = Option::whereIn('id', $optionIds)->get()->keyBy('id');

            foreach ($validated['answers'] as $answer) {
                if (!empty($answer['option_id']) && isset($options[$answer['option_id']])) {
                    $totalScore += $options[$answer['option_id']]->score_value;
                }

                $answersData[] = [
                    'attempt_id' => $attempt->id,
                    'question_id' => $answer['question_id'],
                    'option_id' => $answer['option_id'] ?? null,
                    'text_answer' => $answer['text_answer'] ?? null,
                    'created_at' => now(),
                    'updated_at' => now(),
                ];
            }

            Answer::upsert(
                $answersData,
                ['attempt_id', 'question_id'],
                ['option_id', 'text_answer', 'updated_at']
            );

            $attempt->update(['total_score' => $totalScore]);

            // ═══════════════════════════════════════════════════
            // ✅ بخش محاسبه فرمول‌ها با پشتیبانی از فرمول در فرمول
            // ═══════════════════════════════════════════════════

            $formulaResults = []; // ← نتایج برای استفاده در فرمول‌های بعدی
            $formulaResultsDB = []; // ← برای بازگشت در پاسخ JSON

            // گرفتن فرمول‌ها به ترتیب اولویت (فرمول‌های پایه اول، وابسته بعد)
            $formulas = Formula::where('test_id', $test->id)
                ->where('is_active', true)
                ->orderBy('priority', 'asc') // ← اولویت پایین‌تر = محاسبه زودتر
                ->get();

            foreach ($formulas as $formula) {
                // ۱. آماده‌سازی متغیرهای سوال از پاسخ‌های کاربر
                $variables = $this->prepareVariables($formula, $answersMap, $options);

                // ۲. محاسبه فرمول + passing نتایج فرمول‌های قبلی (برای فرمول در فرمول)
                $calcResult = $this->calculator->calculate(
                    $formula->formula_expression,
                    $variables,
                    $formulaResults // ← اینجا نتایج فرمول‌های قبلی را می‌دهیم
                );

                // ۳. ذخیره نتیجه برای استفاده در فرمول‌های بعدی
                if ($formula->code) {
                    $formulaResults[$formula->code] = $calcResult;
                }

                // ۴. ذخیره در دیتابیس
                FormulaResult::create([
                    'test_id' => $test->id,
                    'user_id' => 1,
                    'attempt_id' => $attempt->id,
                    'formula_id' => $formula->id,
                    'formula_code' => $formula->code ?? $formula->name,
                    'input_values' => $variables,
                    'expression_snapshot' => $formula->formula_expression,
                    'result_type' => $calcResult['type'] ?? 'unknown',
                    'result_value' => $calcResult['value'] ?? null,
                    'execution_time' => null,
                ]);

                $formulaResultsDB[$formula->code ?? $formula->name] = $calcResult;
            }
            // ═══════════════════════════════════════════════════

            return response()->json([
                'success' => true,
                'message' => 'تست با موفقیت ثبت شد',
                'data' => [
                    'attempt_id' => $attempt->id,
                    'total_score' => $totalScore,
                    'test_title' => $test->title,
                    'formula_results' => $formulaResultsDB,
                ]
            ], 201);
        });
    }

    /**
     * آماده‌سازی متغیرها برای فرمول
     */
    protected function prepareVariables(Formula $formula, $answersMap, $options): array
    {
        $variables = [];
        $config = is_string($formula->formula_config)
            ? json_decode($formula->formula_config, true)
            : ($formula->formula_config ?? []);

        if (!empty($config) && is_array($config)) {
            foreach ($config as $varName => $questionId) {
                // اگر questionId عددی است، یعنی اشاره به سوال دارد
                if (is_numeric($questionId)) {
                    $answer = $answersMap[$questionId] ?? null;
                    if ($answer && !empty($answer['option_id']) && isset($options[$answer['option_id']])) {
                        $variables[$varName] = (float)$options[$answer['option_id']]->score_value;
                    } else {
                        $variables[$varName] = $answer['text_answer'] ?? 0;
                    }
                } else {
                    // اگر مقدار مستقیم است (مثلاً برای تست‌های رشته‌ای)
                    $variables[$varName] = $questionId;
                }
            }
        } else {
            preg_match_all('/\{(\d+)\}/', $formula->formula_expression, $matches);
            foreach ($matches[1] as $questionId) {
                $answer = $answersMap[$questionId] ?? null;
                if ($answer && !empty($answer['option_id']) && isset($options[$answer['option_id']])) {
                    $variables[$questionId] = (float)$options[$answer['option_id']]->score_value;
                } else {
                    $variables[$questionId] = $answer['text_answer'] ?? 0;
                }
            }
        }

        return $variables;
    }
}
