<?php

namespace App\Services\Grading;

use App\Models\CurrentFlag;
use App\Models\ParentMeetingSchedule;
use App\Models\ScoreComment;
use App\Models\Student;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use RuntimeException;

class GradingBelowSixtyService
{
    public function listRows(string $schoolYear, string $semester): array
    {
        $semesterKey = strtolower(trim($semester));
        $rows = DB::table('semester_scores as ss')
            ->select([
                's.id as student_id',
                's.school_id',
                's.firstname',
                's.lastname',
                'cs.class_section_name',
                'ss.homework_avg',
                'ss.project_avg',
                'ss.participation_score',
                DB::raw('COALESCE(ss.test_avg, ss.quiz_avg) as test_avg'),
                'ss.ptap_score',
                'ss.attendance_score',
                'ss.midterm_exam_score',
                'ss.final_exam_score',
                'ss.semester_score',
            ])
            ->join('students as s', 's.id', '=', 'ss.student_id')
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'ss.class_section_id')
            ->where('s.is_active', 1)
            ->where('ss.school_year', $schoolYear)
            ->whereRaw('LOWER(TRIM(ss.semester)) = ?', [$semesterKey])
            ->whereNotNull('ss.semester_score')
            ->where('ss.semester_score', '<', 60)
            ->orderBy('s.lastname', 'ASC')
            ->orderBy('s.firstname', 'ASC')
            ->get()
            ->map(fn ($row) => (array) $row)
            ->all();

        if (empty($rows)) {
            return [];
        }

        $studentIds = array_values(array_unique(array_map(
            static fn ($r) => (int) ($r['student_id'] ?? 0),
            $rows
        )));
        $studentIds = array_values(array_filter($studentIds, static fn ($id) => $id > 0));

        $commentMap = [];
        if (!empty($studentIds)) {
            $commentRows = ScoreComment::query()
                ->select('student_id', 'comment', 'created_at')
                ->where('score_type', 'general')
                ->where('school_year', $schoolYear)
                ->whereRaw('LOWER(TRIM(semester)) = ?', [$semesterKey])
                ->whereIn('student_id', $studentIds)
                ->orderBy('created_at', 'DESC')
                ->get();
            foreach ($commentRows as $row) {
                $sid = (int) $row->student_id;
                if ($sid > 0 && !isset($commentMap[$sid])) {
                    $commentMap[$sid] = (string) ($row->comment ?? '');
                }
            }
        }

        $statusMap = [];
        if (!empty($studentIds)) {
            $flagRows = CurrentFlag::query()
                ->select('student_id', 'flag_state')
                ->where('flag', 'grade')
                ->where('school_year', $schoolYear)
                ->whereRaw('LOWER(TRIM(semester)) = ?', [$semesterKey])
                ->whereIn('student_id', $studentIds)
                ->get();
            foreach ($flagRows as $row) {
                $sid = (int) $row->student_id;
                if ($sid > 0) {
                    $statusMap[$sid] = (string) ($row->flag_state ?? '');
                }
            }
        }

        foreach ($rows as &$row) {
            $sid = (int) ($row['student_id'] ?? 0);
            $row['comment'] = $commentMap[$sid] ?? '';
            $flagState = strtolower(trim((string) ($statusMap[$sid] ?? '')));
            $row['status'] = ($flagState === 'closed' || $flagState === 'canceled') ? 'Closed' : 'Open';
        }
        unset($row);

        return $rows;
    }

    public function emailContext(int $studentId, string $schoolYear, string $semester): array
    {
        $row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester);
        if (empty($row)) {
            throw new RuntimeException('Student record not found for the selected term.');
        }

        $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? ''));
        $subject = $this->buildBelowSixtySubject($studentName, $semester, $schoolYear);
        $parentName = $this->fetchBelowSixtyParentName($studentId);

        $scores = [
            'homework_avg' => $row['homework_avg'] ?? null,
            'project_avg' => $row['project_avg'] ?? null,
            'participation_score' => $row['participation_score'] ?? null,
            'test_avg' => $row['test_avg'] ?? null,
            'ptap_score' => $row['ptap_score'] ?? null,
            'attendance_score' => $row['attendance_score'] ?? null,
            'midterm_exam_score' => $row['midterm_exam_score'] ?? null,
            'semester_score' => $row['semester_score'] ?? null,
        ];

        return [
            'student_id' => $studentId,
            'student_name' => $studentName !== '' ? $studentName : 'Student',
            'parent_name' => $parentName,
            'class_section_name' => $row['class_section_name'] ?? '',
            'semester' => $semester,
            'school_year' => $schoolYear,
            'scores' => $scores,
            'comment' => $row['comment'] ?? '',
            'subject' => $subject,
        ];
    }

    public function sendEmail(array $payload): void
    {
        Event::dispatch('below60.email', $payload);
    }

    public function updateStatus(int $studentId, string $semester, string $schoolYear, string $status, string $note, ?int $userId): void
    {
        $status = ucfirst(strtolower($status));
        if (!in_array($status, ['Open', 'Closed'], true)) {
            throw new RuntimeException('Invalid status.');
        }

        $semesterKey = strtolower(trim($semester));
        $existing = CurrentFlag::query()
            ->where('student_id', $studentId)
            ->where('flag', 'grade')
            ->where('school_year', $schoolYear)
            ->whereRaw('LOWER(TRIM(semester)) = ?', [$semesterKey])
            ->first();

        $now = now();

        if ($existing) {
            $data = [
                'flag_state' => $status,
                'flag_datetime' => $now,
                'updated_at' => $now,
            ];
            if ($status === 'Open') {
                $data['updated_by_open'] = $userId;
                if ($note !== '') {
                    $prev = (string) ($existing->open_description ?? '');
                    $data['open_description'] = trim($prev . PHP_EOL . $note);
                }
            } else {
                $data['updated_by_closed'] = $userId;
                if ($note !== '') {
                    $prev = (string) ($existing->close_description ?? '');
                    $data['close_description'] = trim($prev . PHP_EOL . $note);
                }
            }
            $existing->update($data);
            return;
        }

        $row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester);
        $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? ''));
        $grade = (string) ($row['class_section_name'] ?? '');
        $data = [
            'student_id' => $studentId,
            'student_name' => $studentName !== '' ? $studentName : 'Student',
            'grade' => $grade,
            'flag' => 'grade',
            'flag_datetime' => $now,
            'flag_state' => $status,
            'semester' => $semester,
            'school_year' => $schoolYear,
            'updated_at' => $now,
        ];
        if ($status === 'Open') {
            $data['updated_by_open'] = $userId;
            if ($note !== '') {
                $data['open_description'] = $note;
            }
        } else {
            $data['updated_by_closed'] = $userId;
            if ($note !== '') {
                $data['close_description'] = $note;
            }
        }

        CurrentFlag::query()->create($data);
    }

    public function meetingContext(int $studentId, string $schoolYear, string $semester): array
    {
        $context = $this->fetchBelowSixtyMeetingContext($studentId, $schoolYear, $semester);
        if (empty($context)) {
            throw new RuntimeException('Student record not found for the selected term.');
        }

        return $context + [
            'student_id' => $studentId,
            'semester' => $semester,
            'school_year' => $schoolYear,
        ];
    }

    public function saveMeeting(array $payload, ?int $userId): void
    {
        $studentId = (int) ($payload['student_id'] ?? 0);
        $semester = (string) ($payload['semester'] ?? '');
        $schoolYear = (string) ($payload['school_year'] ?? '');
        $date = trim((string) ($payload['date'] ?? ''));
        $time = trim((string) ($payload['time'] ?? ''));
        $notes = trim((string) ($payload['notes'] ?? ''));

        if ($studentId <= 0 || $semester === '' || $schoolYear === '' || $date === '') {
            throw new RuntimeException('Missing required fields.');
        }

        $context = $this->fetchBelowSixtyMeetingContext($studentId, $schoolYear, $semester);
        if (empty($context)) {
            throw new RuntimeException('Student record not found for the selected term.');
        }

        ParentMeetingSchedule::query()->create([
            'student_id' => $studentId,
            'parent_user_id' => $context['parent_user_id'] ?? null,
            'parent_name' => $context['parent_name'],
            'student_name' => $context['student_name'],
            'class_section_name' => $context['class_section_name'],
            'date' => $date,
            'time' => $time !== '' ? $time : null,
            'notes' => $notes !== '' ? $notes : null,
            'semester' => $semester,
            'school_year' => $schoolYear,
            'status' => 'scheduled',
            'created_by' => $userId,
        ]);
    }

    private function fetchBelowSixtyEmailRow(int $studentId, string $schoolYear, string $semester): array
    {
        $semesterKey = strtolower(trim($semester));
        $row = DB::table('semester_scores as ss')
            ->select([
                's.id as student_id',
                's.firstname',
                's.lastname',
                'cs.class_section_name',
                'ss.homework_avg',
                'ss.project_avg',
                'ss.participation_score',
                DB::raw('COALESCE(ss.test_avg, ss.quiz_avg) as test_avg'),
                'ss.ptap_score',
                'ss.attendance_score',
                'ss.midterm_exam_score',
                'ss.semester_score',
            ])
            ->join('students as s', 's.id', '=', 'ss.student_id')
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'ss.class_section_id')
            ->where('ss.school_year', $schoolYear)
            ->where('ss.student_id', $studentId)
            ->where('s.is_active', 1)
            ->whereRaw('LOWER(TRIM(ss.semester)) = ?', [$semesterKey])
            ->first();

        if (!$row) {
            return [];
        }

        $commentRow = ScoreComment::query()
            ->select('comment')
            ->where('score_type', 'general')
            ->where('school_year', $schoolYear)
            ->whereRaw('LOWER(TRIM(semester)) = ?', [$semesterKey])
            ->where('student_id', $studentId)
            ->orderBy('created_at', 'DESC')
            ->first();

        $row = (array) $row;
        $row['comment'] = (string) ($commentRow?->comment ?? '');

        return $row;
    }

    private function fetchBelowSixtyParentName(int $studentId): string
    {
        $parentName = 'Parent/Guardian';
        try {
            $rows = DB::select(
                "SELECT u.firstname, u.lastname
                   FROM family_students fs
                   JOIN family_guardians fg ON fg.family_id = fs.family_id
                   JOIN users u ON u.id = fg.user_id
                  WHERE fs.student_id = ?
                  ORDER BY fg.is_primary DESC, u.lastname, u.firstname
                  LIMIT 1",
                [$studentId]
            );
            if (!empty($rows[0])) {
                $candidate = trim((string) ($rows[0]->firstname ?? '') . ' ' . (string) ($rows[0]->lastname ?? ''));
                if ($candidate !== '') {
                    $parentName = $candidate;
                }
            }
        } catch (\Throwable $e) {
        }
        return $parentName;
    }

    private function buildBelowSixtySubject(string $studentName, string $semester, string $schoolYear): string
    {
        $subject = 'Student Performance Alert';
        if ($studentName !== '') {
            $subject .= ' — ' . $studentName;
        }
        if ($semester !== '' || $schoolYear !== '') {
            $subject .= ' (' . trim($semester . ' ' . $schoolYear) . ')';
        }
        return $subject;
    }

    private function fetchBelowSixtyMeetingContext(int $studentId, string $schoolYear, string $semester): array
    {
        $row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester);
        if (empty($row)) {
            return [];
        }

        $parentName = 'Parent/Guardian';
        $parentUserId = null;
        try {
            $pRows = DB::select(
                "SELECT u.id AS user_id, u.firstname, u.lastname
                   FROM family_students fs
                   JOIN family_guardians fg ON fg.family_id = fs.family_id
                   JOIN users u ON u.id = fg.user_id
                  WHERE fs.student_id = ?
                  ORDER BY fg.is_primary DESC, u.lastname, u.firstname
                  LIMIT 1",
                [$studentId]
            );
            if (!empty($pRows[0])) {
                $parentUserId = (int) ($pRows[0]->user_id ?? 0) ?: null;
                $parentName = trim((string) ($pRows[0]->firstname ?? '') . ' ' . (string) ($pRows[0]->lastname ?? ''));
                if ($parentName === '') {
                    $parentName = 'Parent/Guardian';
                }
            }
        } catch (\Throwable $e) {
        }

        if ($parentUserId === null) {
            try {
                $srow = DB::selectOne(
                    "SELECT s.parent_id, u.firstname, u.lastname
                       FROM students s
                       LEFT JOIN users u ON u.id = s.parent_id
                      WHERE s.id = ?
                      LIMIT 1",
                    [$studentId]
                );
                if (!empty($srow)) {
                    $parentUserId = (int) ($srow->parent_id ?? 0) ?: null;
                    $fallbackName = trim((string) ($srow->firstname ?? '') . ' ' . (string) ($srow->lastname ?? ''));
                    if ($fallbackName !== '') {
                        $parentName = $fallbackName;
                    }
                }
            } catch (\Throwable $e) {
            }
        }

        $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? ''));

        return [
            'student_name' => $studentName !== '' ? $studentName : 'Student',
            'parent_name' => $parentName,
            'parent_user_id' => $parentUserId,
            'class_section_name' => (string) ($row['class_section_name'] ?? ''),
        ];
    }
}
