<?php
declare(strict_types=1);

namespace App\Support;

use App\Core\Database;
use PDO;
use Throwable;

final class AssessmentStore
{
    private ?PDO $pdo;
    private array $questionIdMap = [];

    public function __construct()
    {
        $this->pdo = (new Database())->connection();
    }

    public function startSession(array $participant, array $questions): array
    {
        if (!$this->pdo instanceof PDO) {
            return ['id' => null, 'reference' => null];
        }

        try {
            $this->seedReferenceData();

            $reference = $this->sessionReference();
            $statement = $this->pdo->prepare(
                'INSERT INTO test_sessions (reference, full_name, email, phone, preferred_language, status, started_at)
                 VALUES (:reference, :full_name, :email, :phone, :language, :status, :started_at)'
            );
            $statement->execute([
                'reference' => $reference,
                'full_name' => $participant['full_name'],
                'email' => $participant['email'],
                'phone' => $participant['phone'],
                'language' => $participant['language'],
                'status' => 'in_progress',
                'started_at' => date('Y-m-d H:i:s'),
            ]);

            return [
                'id' => (int) $this->pdo->lastInsertId(),
                'reference' => $reference,
            ];
        } catch (Throwable) {
            return ['id' => null, 'reference' => null];
        }
    }

    public function saveAnswer(?int $testSessionId, array $question, int $answer): void
    {
        if (!$this->pdo instanceof PDO || $testSessionId === null) {
            return;
        }

        try {
            $questionId = $this->questionIdFor($question);

            if ($questionId === null) {
                return;
            }

            $statement = $this->pdo->prepare(
                'INSERT INTO participant_answers (test_session_id, question_id, answer_value, answered_at)
                 VALUES (:test_session_id, :question_id, :answer_value, :answered_at)
                 ON DUPLICATE KEY UPDATE answer_value = VALUES(answer_value), answered_at = VALUES(answered_at)'
            );
            $statement->execute([
                'test_session_id' => $testSessionId,
                'question_id' => $questionId,
                'answer_value' => $answer,
                'answered_at' => date('Y-m-d H:i:s'),
            ]);
        } catch (Throwable) {
        }
    }

    public function completeSession(?int $testSessionId): void
    {
        if (!$this->pdo instanceof PDO || $testSessionId === null) {
            return;
        }

        try {
            $statement = $this->pdo->prepare(
                'UPDATE test_sessions SET status = :status, completed_at = :completed_at WHERE id = :id'
            );
            $statement->execute([
                'status' => 'completed',
                'completed_at' => date('Y-m-d H:i:s'),
                'id' => $testSessionId,
            ]);
        } catch (Throwable) {
        }
    }

    private function seedReferenceData(): void
    {
        if (!$this->pdo instanceof PDO) {
            return;
        }

        $languageStatement = $this->pdo->prepare(
            'INSERT INTO languages (code, name) VALUES (:code, :name) ON DUPLICATE KEY UPDATE name = VALUES(name)'
        );
        foreach ((array) config('supported_languages', []) as $code => $name) {
            $languageStatement->execute(['code' => $code, 'name' => $name]);
        }

        $areaStatement = $this->pdo->prepare(
            'INSERT INTO riasec_areas (code, name, color_hex, sort_order)
             VALUES (:code, :name, :color_hex, :sort_order)
             ON DUPLICATE KEY UPDATE name = VALUES(name), color_hex = VALUES(color_hex), sort_order = VALUES(sort_order)'
        );
        $sortOrder = 1;
        foreach ((array) config('riasec_areas', []) as $code => $area) {
            $areaStatement->execute([
                'code' => $code,
                'name' => $area['name'],
                'color_hex' => $area['color'],
                'sort_order' => $sortOrder++,
            ]);
        }
    }

    private function questionIdFor(array $question): ?int
    {
        return $this->questionIdBySourceKey((string) ($question['id'] ?? ''));
    }

    private function questionIdBySourceKey(string $sourceKey): ?int
    {
        if (isset($this->questionIdMap[$sourceKey])) {
            return $this->questionIdMap[$sourceKey];
        }

        if (!$this->pdo instanceof PDO || $sourceKey === '') {
            return null;
        }

        $statement = $this->pdo->prepare('SELECT id FROM questions WHERE source_key = :source_key LIMIT 1');
        $statement->execute(['source_key' => $sourceKey]);
        $questionId = $statement->fetchColumn();

        if ($questionId === false) {
            return null;
        }

        $this->questionIdMap[$sourceKey] = (int) $questionId;

        return $this->questionIdMap[$sourceKey];
    }

    private function sessionReference(): string
    {
        return 'TEST-' . date('Ymd-His') . '-' . strtoupper(substr(bin2hex(random_bytes(3)), 0, 6));
    }
}