<?php

declare(strict_types=1);

namespace App\Services;

use App\Core\FileStore;

class CommunicationService
{
    private FileStore $questions;
    private FileStore $notifications;
    private AuthService $auth;
    private CourseService $courses;
    private CourseContentService $content;
    private EnrollmentService $enrollments;
    private ActivityLogService $logs;

    public function __construct()
    {
        $this->questions = new FileStore(storage_path('data/course_questions.json'));
        $this->notifications = new FileStore(storage_path('data/notifications.json'));
        $this->auth = new AuthService();
        $this->courses = new CourseService();
        $this->content = new CourseContentService();
        $this->enrollments = new EnrollmentService();
        $this->logs = new ActivityLogService();
    }

    public function askQuestion(int $courseId, ?int $lessonId, array $student, string $body): array
    {
        if (($student['role'] ?? '') !== 'student') {
            return ['ok' => false, 'error' => 'Apenas alunos podem fazer perguntas.'];
        }

        $course = $this->courses->find($courseId);

        if (!$course || !$this->enrollments->findEnrollment((int) $student['id'], $courseId)) {
            return ['ok' => false, 'error' => 'Precisa estar inscrito no curso para perguntar.'];
        }

        $body = trim($body);

        if ($body === '') {
            return ['ok' => false, 'error' => 'Escreva a sua pergunta.'];
        }

        if (strlen($body) > 1500) {
            return ['ok' => false, 'error' => 'Pergunta demasiado longa.'];
        }

        $lessonTitle = '';

        if ($lessonId) {
            $lesson = $this->content->lesson($lessonId);

            if (!$lesson || (int) ($lesson['course_id'] ?? 0) !== $courseId) {
                return ['ok' => false, 'error' => 'Aula invalida.'];
            }

            $lessonTitle = $lesson['title'] ?? '';
        }

        $question = $this->questions->insert([
            'course_id' => $courseId,
            'course_title' => $course['title'],
            'lesson_id' => $lessonId,
            'lesson_title' => $lessonTitle,
            'student_id' => (int) $student['id'],
            'student_name' => $student['name'] ?? 'Aluno',
            'student_email' => $student['email'] ?? '',
            'body' => $body,
            'answer' => '',
            'answered_by' => null,
            'answered_by_name' => '',
            'answered_at' => null,
            'status' => 'open',
            'created_at' => date('c'),
            'updated_at' => date('c'),
        ]);

        foreach ($this->recipientsForCourse($course) as $recipientId) {
            $this->notify($recipientId, 'Nova pergunta no curso', "{$student['name']} perguntou em {$course['title']}.", '/communication/questions');
        }

        $this->logs->log('question_created', "Pergunta criada no curso {$course['title']}.", (int) $student['id']);

        return ['ok' => true, 'question' => $question];
    }

    public function answerQuestion(int $id, array $user, string $answer): array
    {
        $records = $this->questions->all();
        $updated = null;

        foreach ($records as $index => $question) {
            if ((int) ($question['id'] ?? 0) !== $id) {
                continue;
            }

            if (!$this->canManageQuestion($question, $user)) {
                return ['ok' => false, 'error' => 'Nao tem permissao para responder esta pergunta.'];
            }

            $answer = trim($answer);

            if ($answer === '') {
                return ['ok' => false, 'error' => 'Escreva a resposta.'];
            }

            if (strlen($answer) > 2000) {
                return ['ok' => false, 'error' => 'Resposta demasiado longa.'];
            }

            $records[$index] = array_merge($question, [
                'answer' => $answer,
                'answered_by' => (int) $user['id'],
                'answered_by_name' => $user['name'] ?? role_label($user['role'] ?? 'Utilizador'),
                'answered_at' => date('c'),
                'status' => 'answered',
                'updated_at' => date('c'),
            ]);
            $updated = $records[$index];
            break;
        }

        if (!$updated) {
            return ['ok' => false, 'error' => 'Pergunta nao encontrada.'];
        }

        $this->questions->save($records);
        $this->notify((int) $updated['student_id'], 'Pergunta respondida', "A sua pergunta em {$updated['course_title']} foi respondida.", '/notifications');
        $this->logs->log('question_answered', "Pergunta #{$id} respondida.", (int) $user['id']);

        return ['ok' => true, 'question' => $updated];
    }

    public function questionsForLesson(int $lessonId): array
    {
        return $this->sortQuestions(array_filter(
            $this->questions->all(),
            fn (array $question): bool => (int) ($question['lesson_id'] ?? 0) === $lessonId
        ));
    }

    public function questionsForStudent(int $studentId): array
    {
        return $this->sortQuestions(array_filter(
            $this->questions->all(),
            fn (array $question): bool => (int) ($question['student_id'] ?? 0) === $studentId
        ));
    }

    public function questionsForUser(array $user, array $filters = []): array
    {
        $status = (string) ($filters['status'] ?? '');
        $search = strtolower(trim((string) ($filters['search'] ?? '')));

        $items = array_filter($this->questions->all(), fn (array $question): bool => $this->canManageQuestion($question, $user));

        if ($status !== '') {
            $items = array_filter($items, fn (array $question): bool => ($question['status'] ?? '') === $status);
        }

        if ($search !== '') {
            $items = array_filter($items, function (array $question) use ($search): bool {
                $haystack = strtolower(
                    ($question['course_title'] ?? '') . ' ' .
                    ($question['lesson_title'] ?? '') . ' ' .
                    ($question['student_name'] ?? '') . ' ' .
                    ($question['body'] ?? '') . ' ' .
                    ($question['answer'] ?? '')
                );

                return str_contains($haystack, $search);
            });
        }

        return $this->sortQuestions($items);
    }

    public function notificationsForUser(int $userId): array
    {
        $items = array_values(array_filter(
            $this->notifications->all(),
            fn (array $notification): bool => (int) ($notification['user_id'] ?? 0) === $userId
        ));

        usort($items, fn (array $a, array $b): int => strcmp($b['created_at'] ?? '', $a['created_at'] ?? ''));

        return $items;
    }

    public function unreadCount(int $userId): int
    {
        return count(array_filter(
            $this->notifications->all(),
            fn (array $notification): bool => (int) ($notification['user_id'] ?? 0) === $userId && empty($notification['read_at'])
        ));
    }

    public function markRead(int $id, int $userId): void
    {
        $records = $this->notifications->all();

        foreach ($records as $index => $notification) {
            if ((int) ($notification['id'] ?? 0) === $id && (int) ($notification['user_id'] ?? 0) === $userId) {
                $records[$index]['read_at'] = date('c');
                $records[$index]['updated_at'] = date('c');
                break;
            }
        }

        $this->notifications->save($records);
    }

    public function markAllRead(int $userId): void
    {
        $records = $this->notifications->all();

        foreach ($records as $index => $notification) {
            if ((int) ($notification['user_id'] ?? 0) === $userId && empty($notification['read_at'])) {
                $records[$index]['read_at'] = date('c');
                $records[$index]['updated_at'] = date('c');
            }
        }

        $this->notifications->save($records);
    }

    private function notify(int $userId, string $title, string $body, string $url): void
    {
        if ($userId <= 0) {
            return;
        }

        $this->notifications->insert([
            'user_id' => $userId,
            'title' => $title,
            'body' => $body,
            'url' => $url,
            'read_at' => null,
            'created_at' => date('c'),
            'updated_at' => date('c'),
        ]);
    }

    private function canManageQuestion(array $question, array $user): bool
    {
        if (($user['role'] ?? '') === 'admin') {
            return true;
        }

        if (!in_array($user['role'] ?? '', ['instructor', 'institution'], true)) {
            return false;
        }

        $course = $this->courses->find((int) ($question['course_id'] ?? 0));

        return $course && (int) ($course['owner_id'] ?? 0) === (int) ($user['id'] ?? 0);
    }

    private function recipientsForCourse(array $course): array
    {
        if (($course['owner_type'] ?? '') === 'platform') {
            return [1];
        }

        return [(int) ($course['owner_id'] ?? 0), 1];
    }

    private function sortQuestions(iterable $items): array
    {
        $items = array_values(is_array($items) ? $items : iterator_to_array($items));
        usort($items, fn (array $a, array $b): int => strcmp($b['updated_at'] ?? '', $a['updated_at'] ?? ''));

        return $items;
    }
}
