<?php

namespace App\Services\Administrator;

use App\Models\AttendanceDay;
use App\Models\ScoreComment;
use App\Models\SemesterScore;
use App\Models\TeacherSubmissionNotificationHistory;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class TeacherSubmissionReportService
{
    public function __construct(
        protected AdministratorSharedService $shared,
        protected TeacherSubmissionSupportService $support
    ) {
    }

    public function report(): array
    {
        $semester = $this->shared->getSemester();
        $schoolYear = $this->shared->getSchoolYear();

        $assignmentRows = DB::table('teacher_class as tc')
            ->select([
                'tc.class_section_id',
                'cs.class_section_name',
                'tc.teacher_id',
                'u.firstname',
                'u.lastname',
                'tc.position',
            ])
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
            ->leftJoin('users as u', 'u.id', '=', 'tc.teacher_id')
            ->where('tc.school_year', $schoolYear)
            ->where('tc.semester', $semester)
            ->orderBy('cs.class_section_name')
            ->get()
            ->map(fn ($r) => (array) $r)
            ->all();

        $teachersBySection = [];
        foreach ($assignmentRows as $assignment) {
            $sectionId = (int) ($assignment['class_section_id'] ?? 0);
            if ($sectionId <= 0) {
                continue;
            }

            $positionKey = strtolower(trim((string) ($assignment['position'] ?? '')));
            $roleKey = $positionKey !== '' ? $positionKey : 'teacher';

            $positionLabel = match ($roleKey) {
                'ta' => 'TA',
                'main' => 'Main',
                default => $roleKey !== '' ? ucfirst($roleKey) : 'Teacher',
            };

            $teacherFullName = trim(($assignment['firstname'] ?? '') . ' ' . ($assignment['lastname'] ?? ''));
            $teacherId = (int) ($assignment['teacher_id'] ?? 0);

            if ($teacherFullName === '' || $teacherId <= 0) {
                continue;
            }

            if (!isset($teachersBySection[$sectionId])) {
                $teachersBySection[$sectionId] = [
                    'class_section' => $assignment['class_section_name'] ?? "Section {$sectionId}",
                    'teachers' => [],
                ];
            }

            $teachersBySection[$sectionId]['teachers'][] = [
                'id' => $teacherId,
                'label' => "{$positionLabel}: {$teacherFullName}",
                'role_key' => $roleKey,
            ];
        }

        $today = now()->format('Y-m-d');
        $rows = [];
        $totalStatuses = 0;
        $missingItemCount = 0;
        $allTeacherIds = [];
        $allClassSectionIds = [];

        foreach ($teachersBySection as $classSectionId => $section) {
            $classSectionId = (int) $classSectionId;
            if ($classSectionId <= 0) {
                continue;
            }

            $studentIds = DB::table('student_class')
                ->where('class_section_id', $classSectionId)
                ->where('semester', $semester)
                ->where('school_year', $schoolYear)
                ->pluck('student_id')
                ->map(fn ($id) => (int) $id)
                ->filter()
                ->values()
                ->all();

            $expected = count($studentIds);

            $midtermStudents = [];
            $participationStudents = [];

            $scoreRecords = SemesterScore::query()
                ->where('class_section_id', $classSectionId)
                ->where('semester', $semester)
                ->where('school_year', $schoolYear)
                ->get();

            foreach ($scoreRecords as $score) {
                $sid = (int) ($score->student_id ?? 0);
                if ($sid <= 0 || ($expected > 0 && !in_array($sid, $studentIds, true))) {
                    continue;
                }

                if (trim((string) ($score->midterm_exam_score ?? '')) !== '') {
                    $midtermStudents[$sid] = true;
                }

                if (trim((string) ($score->participation_score ?? '')) !== '') {
                    $participationStudents[$sid] = true;
                }
            }

            $midtermCommentStudents = [];
            $ptapCommentStudents = [];

            if (!empty($studentIds)) {
                $comments = ScoreComment::query()
                    ->select('student_id', 'score_type', 'comment')
                    ->whereIn('student_id', $studentIds)
                    ->where('semester', $semester)
                    ->where('school_year', $schoolYear)
                    ->whereIn('score_type', ['midterm', 'ptap'])
                    ->get();

                foreach ($comments as $comment) {
                    $sid = (int) ($comment->student_id ?? 0);
                    if ($sid <= 0) {
                        continue;
                    }

                    $text = trim((string) ($comment->comment ?? ''));
                    if ($text === '') {
                        continue;
                    }

                    $type = strtolower(trim((string) ($comment->score_type ?? '')));
                    if ($type === 'midterm') {
                        $midtermCommentStudents[$sid] = true;
                    }
                    if ($type === 'ptap') {
                        $ptapCommentStudents[$sid] = true;
                    }
                }
            }

            $attendanceRow = AttendanceDay::query()
                ->where('class_section_id', $classSectionId)
                ->where('semester', $semester)
                ->where('school_year', $schoolYear)
                ->whereDate('date', $today)
                ->first();

            $attendanceSubmitted = $attendanceRow
                && in_array(strtolower((string) ($attendanceRow->status ?? '')), ['submitted', 'published', 'finalized'], true);

            $teacherList = $section['teachers'] ?? [];
            usort(
                $teacherList,
                fn ($a, $b) => $this->support->teacherRolePriority($a['role_key'] ?? 'teacher')
                    <=> $this->support->teacherRolePriority($b['role_key'] ?? 'teacher')
            );

            foreach ($teacherList as $teacherEntry) {
                if (!empty($teacherEntry['id'])) {
                    $allTeacherIds[] = $teacherEntry['id'];
                }
            }
            $allClassSectionIds[] = $classSectionId;

            $midtermScoreStatus = $this->support->submissionStatus(count($midtermStudents), $expected);
            $midtermCommentStatus = $this->support->submissionStatus(count($midtermCommentStudents), $expected);
            $participationStatus = $this->support->submissionStatus(count($participationStudents), $expected);
            $ptapCommentStatus = $this->support->submissionStatus(count($ptapCommentStudents), $expected);
            $attendanceStatus = $this->support->attendanceStatus($attendanceSubmitted, $expected);

            $statusDetails = [
                'midterm_score_status' => $midtermScoreStatus,
                'midterm_comment_status' => $midtermCommentStatus,
                'participation_status' => $participationStatus,
                'ptap_comment_status' => $ptapCommentStatus,
                'attendance_status' => $attendanceStatus,
            ];

            $missingItemsForSection = $this->support->buildMissingItems($statusDetails);
            $missingItemCount += count($missingItemsForSection);
            $totalStatuses += count($statusDetails);

            $rows[] = [
                'class_section' => $section['class_section'] ?? "Section {$classSectionId}",
                'class_section_id' => $classSectionId,
                'teachers' => array_values($teacherList),
                'midterm_score_status' => $midtermScoreStatus,
                'midterm_comment_status' => $midtermCommentStatus,
                'participation_status' => $participationStatus,
                'ptap_comment_status' => $ptapCommentStatus,
                'attendance_status' => $attendanceStatus,
                'missing_items' => $missingItemsForSection,
                'student_count' => $expected,
            ];
        }

        $historyMap = $this->notificationHistoryMap($allTeacherIds, $allClassSectionIds);

        $summary = [
            'total_items' => $totalStatuses,
            'missing_items' => $missingItemCount,
            'submitted_items' => max(0, $totalStatuses - $missingItemCount),
            'submission_percentage' => $totalStatuses > 0
                ? (int) round((($totalStatuses - $missingItemCount) / $totalStatuses) * 100)
                : 100,
        ];

        return [
            'rows' => $rows,
            'semester' => $semester,
            'schoolYear' => $schoolYear,
            'notificationHistory' => $historyMap,
            'summary' => $summary,
        ];
    }

    protected function notificationHistoryMap(array $allTeacherIds, array $allClassSectionIds): array
    {
        $historyMap = [];
        $teacherIds = array_values(array_unique($allTeacherIds));
        $classSectionIds = array_values(array_unique($allClassSectionIds));

        if (empty($teacherIds) || empty($classSectionIds)) {
            return $historyMap;
        }

        $historyRecords = TeacherSubmissionNotificationHistory::query()
            ->select('teacher_submission_notification_history.*', 'u.firstname', 'u.lastname')
            ->leftJoin('users as u', 'u.id', '=', 'teacher_submission_notification_history.admin_id')
            ->where('notification_category', 'teacher_submissions')
            ->whereIn('teacher_submission_notification_history.teacher_id', $teacherIds)
            ->whereIn('teacher_submission_notification_history.class_section_id', $classSectionIds)
            ->orderByDesc('sent_at')
            ->get();

        foreach ($historyRecords as $record) {
            $sectionId = (int) ($record->class_section_id ?? 0);
            $teacherId = (int) ($record->teacher_id ?? 0);

            if ($sectionId <= 0 || $teacherId <= 0) {
                continue;
            }

            $adminName = trim(($record->firstname ?? '') . ' ' . ($record->lastname ?? ''));
            if ($adminName === '') {
                $adminName = 'Administrator';
            }

            $historyMap[$sectionId][$teacherId][] = [
                'sent_at_text' => $record->sent_at ? Carbon::parse($record->sent_at)->format('M j, Y g:i A') : '',
                'admin_name' => $adminName,
                'status' => strtolower((string) ($record->status ?? 'sent')),
            ];
        }

        foreach ($historyMap as &$teachersHistory) {
            foreach ($teachersHistory as &$entries) {
                $entries = array_slice($entries, 0, 3);
            }
        }

        return $historyMap;
    }
}
