<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Support\AssessmentStore;
use App\Support\QuestionStore;
use App\Support\ReportBuilder;
use App\Support\ReportStore;

final class ParticipantController
{
    private QuestionStore $questionStore;
    private AssessmentStore $assessmentStore;
    private ReportBuilder $reportBuilder;
    private ReportStore $reportStore;

    public function __construct()
    {
        $this->questionStore = new QuestionStore();
        $this->assessmentStore = new AssessmentStore();
        $this->reportBuilder = new ReportBuilder();
        $this->reportStore = new ReportStore();
    }

    public function home(): void
    {
        $locale = current_locale();

        render('participant.home', [
            'title' => trans('page_titles.start_test', [], $locale),
            'languages' => config('supported_languages', []),
            'questionCount' => count($this->questionStore->assessmentQuestions($locale)),
        ]);
    }

    public function start(): void
    {
        if (!verify_csrf($_POST['_csrf'] ?? null)) {
            flash('error', trans('alerts.session_expired'));
            redirect('/');
        }

        $input = [
            'full_name' => trim((string) ($_POST['full_name'] ?? '')),
            'email' => trim((string) ($_POST['email'] ?? '')),
            'phone' => trim((string) ($_POST['phone'] ?? '')),
            'language' => trim((string) ($_POST['language'] ?? config('default_language'))),
        ];

        set_ui_locale($input['language'], 'participant');

        set_old_input($input);

        $errors = [];

        if ($input['full_name'] === '') {
            $errors[] = trans('alerts.full_name_required');
        }

        if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
            $errors[] = trans('alerts.valid_email_required');
        }

        if ($input['phone'] === '') {
            $errors[] = trans('alerts.phone_required');
        }

        if (!array_key_exists($input['language'], (array) config('supported_languages', []))) {
            $errors[] = trans('alerts.valid_language_required');
        }

        $questions = $this->questionStore->assessmentQuestions($input['language']);

        if ($questions === []) {
            $errors[] = trans('alerts.question_bank_unavailable');
        }

        if ($errors !== []) {
            flash('error', implode(' ', $errors));
            redirect('/');
        }

        clear_old_input();

        $databaseSession = $this->assessmentStore->startSession($input, $questions);

        $_SESSION['participant_test'] = [
            'participant' => $input,
            'questions' => $questions,
            'answers' => [],
            'started_at' => date('Y-m-d H:i:s'),
            'database_session_id' => $databaseSession['id'],
            'database_reference' => $databaseSession['reference'],
        ];

        unset($_SESSION['participant_report']);

        redirect('/participant/test?step=1');
    }

    public function test(): void
    {
        $state = $_SESSION['participant_test'] ?? null;

        if (!is_array($state)) {
            flash('error', trans('alerts.enter_details_first'));
            redirect('/');
        }

        $state = $this->synchronizeTestLocale($state);

        $questions = $state['questions'];
        $answers = $state['answers'];
        $totalQuestions = count($questions);
        $step = max(1, min((int) ($_GET['step'] ?? 1), $totalQuestions));
        $question = $questions[$step - 1];
        $previousStep = $step > 1 ? $step - 1 : null;
        $nextStep = $step < $totalQuestions ? $step + 1 : null;

        render('participant.test', [
            'title' => trans('page_titles.assessment', [], (string) $state['participant']['language']),
            'participant' => $state['participant'],
            'question' => $question,
            'currentStep' => $step,
            'totalQuestions' => $totalQuestions,
            'previousStep' => $previousStep,
            'nextStep' => $nextStep,
            'selectedAnswer' => $answers[$question['id']] ?? null,
            'area' => config('riasec_areas.' . $question['area_code']),
        ]);
    }

    public function answer(): void
    {
        if (!verify_csrf($_POST['_csrf'] ?? null)) {
            flash('error', trans('alerts.session_expired'));
            redirect('/');
        }

        $state = $_SESSION['participant_test'] ?? null;

        if (!is_array($state)) {
            flash('error', trans('alerts.session_not_found'));
            redirect('/');
        }

        $state = $this->synchronizeTestLocale($state);

        $step = max(1, (int) ($_POST['step'] ?? 1));
        $questions = $state['questions'];
        $totalQuestions = count($questions);
        $step = min($step, $totalQuestions);
        $question = $questions[$step - 1];
        $answer = (string) ($_POST['answer'] ?? '');

        if (!in_array($answer, ['1', '0'], true)) {
            flash('error', trans('alerts.choose_answer', [], (string) ($state['participant']['language'] ?? null)));
            redirect('/participant/test?step=' . $step);
        }

        $state['answers'][$question['id']] = (int) $answer;
        $this->assessmentStore->saveAnswer($state['database_session_id'] ?? null, $question, (int) $answer);
        $_SESSION['participant_test'] = $state;

        if ($step >= $totalQuestions) {
            $report = $this->reportBuilder->build($state['participant'], $questions, $state['answers']);
            if (!empty($state['database_reference'])) {
                $report['session_reference'] = $state['database_reference'];
            }

            $_SESSION['participant_report'] = $report;
            $this->assessmentStore->completeSession($state['database_session_id'] ?? null);
            $this->reportStore->save($report, $state['database_session_id'] ?? null);
            redirect('/participant/report');
        }

        redirect('/participant/test?step=' . ($step + 1));
    }

    public function report(): void
    {
        $report = $_SESSION['participant_report'] ?? null;

        if (!is_array($report)) {
            flash('error', trans('alerts.report_immediate_only'));
            redirect('/');
        }

        $locale = current_locale();
        $localizedReport = $this->reportBuilder->localize($report, $locale);

        render('participant.report', [
            'title' => trans('page_titles.your_report', [], $locale),
            'report' => $localizedReport,
            'adminMode' => false,
        ]);
    }

    public function downloadReport(): void
    {
        $report = $_SESSION['participant_report'] ?? null;

        if (!is_array($report)) {
            flash('error', trans('alerts.pdf_immediate_only'));
            redirect('/');
        }

        $localizedReport = $this->reportBuilder->localize($report, current_locale());
        $pdfPath = $this->reportStore->refreshPdf($localizedReport);

        if ($pdfPath === null || !is_file($pdfPath)) {
            flash('error', trans('alerts.pdf_generation_failed', [], (string) $report['participant']['language']));
            redirect('/participant/report');
        }

        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="' . basename($pdfPath) . '"');
        header('Content-Length: ' . filesize($pdfPath));
        readfile($pdfPath);
        exit;
    }

    private function synchronizeTestLocale(array $state): array
    {
        $requestedLocale = current_locale();
        $currentLanguage = (string) ($state['participant']['language'] ?? config('default_language', 'en'));

        if ($requestedLocale === $currentLanguage) {
            return $state;
        }

        $localizedQuestions = $this->questionStore->assessmentQuestions($requestedLocale);

        if ($localizedQuestions === [] || count($localizedQuestions) !== count($state['questions'])) {
            return $state;
        }

        $state['participant']['language'] = $requestedLocale;
        $state['questions'] = $localizedQuestions;
        $_SESSION['participant_test'] = $state;
        set_ui_locale($requestedLocale, 'participant');

        return $state;
    }
}