<?php

namespace App\Services\AttendanceTracking;

use App\Models\AttendanceData;
use App\Models\AttendanceTracking;
use App\Models\Configuration;
use App\Models\Student;
use App\Models\StudentClass;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;

class AttendanceNotificationWorkflowService
{
    protected string $semester;
    protected string $schoolYear;

    public function __construct(
        protected Student $studentModel,
        protected StudentClass $studentClassModel,
        protected AttendanceData $attendanceDataModel,
        protected AttendanceTracking $attendanceTrackingModel,
        protected Configuration $configModel,
        protected AttendanceMailerService $attendanceMailerService,
        protected ViolationRuleEngineService $violationRuleEngine,
        protected AttendanceParentLookupService $parentLookupService,
        protected AttendanceEmailComposerService $emailComposerService,
        protected AttendanceNotificationLogService $notificationLogService
    ) {
        $this->semester   = (string) ($this->configModel->getConfig('semester') ?? '');
        $this->schoolYear = (string) ($this->configModel->getConfig('school_year') ?? '');
    }

    public function record(array $data): array
    {
        $sid        = (int) $data['student_id'];
        $ymd        = substr((string) $data['date'], 0, 10);
        $semester   = $data['semester'] ?? $this->semester;
        $schoolYear = $data['school_year'] ?? $this->schoolYear;
        $subject    = $data['subject_type'] ?? 'Absent';

        $student = $this->studentModel->query()->find($sid)?->toArray() ?? [];
        $parentEmail = $data['parent_email'] ?? '';
        $parentName  = $data['parent_name'] ?? '';

        if (!$parentEmail) {
            $parent = $this->parentLookupService->getPrimaryParentForStudent($sid) ?? [];
            $parentEmail = $parent['email'] ?? '';
            $parentName  = $parent['parent_name'] ?? '';
        }

        if (!$parentEmail) {
            return [
                'success' => false,
                'message' => 'No parent email found for this student.',
                'status'  => 422,
            ];
        }

        [$start, $end] = $this->violationRuleEngine->dayBounds($ymd);

        $row = $this->attendanceTrackingModel->query()
            ->where('student_id', $sid)
            ->where('semester', $semester)
            ->where('school_year', $schoolYear)
            ->where('date', '>=', $start)
            ->where('date', '<', $end)
            ->orderByDesc('date')
            ->first();

        $row = $row?->toArray();

        $consequence = null;
        $reasonTxt = (string) ($row['reason'] ?? '');
        if (preg_match('/\bABS_4\b|dismissal/i', $reasonTxt)) {
            $consequence = 'dismissal';
        } elseif (preg_match('/\bABS_3\b|final_warning/i', $reasonTxt)) {
            $consequence = 'final_warning';
        } elseif (preg_match('/\bABS_2\b|follow_up/i', $reasonTxt)) {
            $consequence = 'follow_up';
        }

        $class = method_exists($this->studentClassModel, 'getClassSectionsByStudentId')
            ? $this->studentClassModel->getClassSectionsByStudentId($sid, $this->schoolYear)
            : [];

        $payload = [
            'student_id'  => $sid,
            'student'     => $student,
            'parent'      => ['email' => $parentEmail, 'name' => $parentName],
            'semester'    => $semester,
            'school_year' => $schoolYear,
            'class'       => $class,
            'now'         => now()->toDateTimeString(),
            'date'        => $ymd,
            'subject'     => $subject,
            'consequence' => $consequence ?: 'follow_up',
        ];

        try {
            $this->attendanceMailerService->queueAttendanceEvent($payload);

            if ($row && !empty($row['id']) && method_exists($this->attendanceTrackingModel, 'markAsNotified')) {
                $this->attendanceTrackingModel->markAsNotified((int) $row['id']);
            }

            return [
                'success' => true,
                'message' => 'Notification queued.',
                'data'    => $payload,
            ];
        } catch (Throwable $e) {
            Log::error('Attendance record queue failed: ' . $e->getMessage());

            return [
                'success' => false,
                'message' => $e->getMessage(),
                'status'  => 500,
            ];
        }
    }

    public function sendAutoEmails(array $violations, ?string $variantOverride = null): array
    {
        $toSend = array_values(array_filter($violations, fn ($v) => ($v['action'] ?? '') === 'auto_email'));

        $sent = 0;
        $skipped = 0;
        $errors = 0;
        $details = [];

        foreach ($toSend as $v) {
            $sid   = (int) ($v['id'] ?? 0);
            $code  = (string) ($v['violation_code'] ?? $v['code'] ?? '');
            $date  = (string) ($v['last_date'] ?? '');
            $to    = trim((string) ($v['parent_email'] ?? ''));
            $pname = (string) ($v['parent_name'] ?? '');

            if ($sid <= 0 || !$code || !$date || !$to) {
                $errors++;
                $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'missing data'];
                continue;
            }

            if ($this->notificationLogService->notificationAlreadySent($sid, $code, $date, 'email', $to)) {
                $skipped++;
                $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'duplicate'];
                continue;
            }

            $parent  = $this->parentLookupService->getPrimaryParentForStudent($sid);
            $context = $this->emailComposerService->buildTemplateContext($v, $parent);
            $variant = $this->emailComposerService->pickVariant($code, $variantOverride);
            $tpl     = $this->emailComposerService->renderTemplate($code, $variant, $context);

            if (!$tpl) {
                [$subject, $body] = $this->emailComposerService->buildFallbackAutoEmail($code, $v, $pname);
            } else {
                [$subject, $body] = $tpl;
            }

            $wrapped = $this->emailComposerService->renderWithEmailLayout($subject, $body);
            $anyOk = false;

            try {
                $ok = $this->attendanceMailerService->send($to, $subject, $wrapped);

                if ($ok) {
                    $anyOk = true;
                    $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'sent'];
                    $this->notificationLogService->logNotification(
                        $sid,
                        $code,
                        $date,
                        'email',
                        $to,
                        $subject,
                        'sent',
                        'OK',
                        $this->semester,
                        $this->schoolYear
                    );
                } else {
                    $errors++;
                    $this->notificationLogService->logNotification(
                        $sid,
                        $code,
                        $date,
                        'email',
                        $to,
                        $subject,
                        'failed',
                        'send returned false',
                        $this->semester,
                        $this->schoolYear
                    );
                    $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'failed'];
                }
            } catch (Throwable $e) {
                $errors++;
                $this->notificationLogService->logNotification(
                    $sid,
                    $code,
                    $date,
                    'email',
                    $to,
                    $subject,
                    'failed',
                    $e->getMessage(),
                    $this->semester,
                    $this->schoolYear
                );
                $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: ' . $e->getMessage()];
            }

            try {
                $sec = $this->parentLookupService->getSecondaryParentForStudent($sid, $this->schoolYear);
                $to2 = trim((string) ($sec['email'] ?? ''));

                if ($to2 !== '' && strcasecmp($to2, $to) !== 0) {
                    if ($this->notificationLogService->notificationAlreadySent($sid, $code, $date, 'email', $to2)) {
                        $skipped++;
                        $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'duplicate_cc'];
                    } else {
                        $ok2 = $this->attendanceMailerService->send($to2, $subject, $wrapped);
                        if ($ok2) {
                            $anyOk = true;
                            $this->notificationLogService->logNotification(
                                $sid,
                                $code,
                                $date,
                                'email',
                                $to2,
                                $subject,
                                'sent',
                                'OK',
                                $this->semester,
                                $this->schoolYear
                            );
                            $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_sent'];
                        } else {
                            $errors++;
                            $this->notificationLogService->logNotification(
                                $sid,
                                $code,
                                $date,
                                'email',
                                $to2,
                                $subject,
                                'failed',
                                'send returned false',
                                $this->semester,
                                $this->schoolYear
                            );
                            $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_failed'];
                        }
                    }
                }
            } catch (Throwable $e) {
                $errors++;
                $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: ' . $e->getMessage()];
            }

            if ($anyOk) {
                $sent++;

                if (method_exists($this->attendanceTrackingModel, 'markRuleAsNotified')) {
                    $this->attendanceTrackingModel->markRuleAsNotified(
                        $sid,
                        $code,
                        $date,
                        $this->semester,
                        $this->schoolYear
                    );
                }

                $allDates = [];
                $absDates  = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['absences'] ?? []));
                $lateDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['lates'] ?? []));

                if (!empty($absDates)) {
                    $allDates = array_merge($allDates, $absDates);
                }
                if (!empty($lateDates)) {
                    $allDates = array_merge($allDates, $lateDates);
                }
                if (empty($allDates)) {
                    $allDates[] = substr($date, 0, 10);
                }

                if (method_exists($this->attendanceDataModel, 'markReportedAndNotified')) {
                    $this->attendanceDataModel->markReportedAndNotified(
                        $sid,
                        $allDates,
                        $this->semester,
                        $this->schoolYear
                    );
                }
            }
        }

        return [
            'success' => true,
            'sent'    => $sent,
            'skipped' => $skipped,
            'errors'  => $errors,
            'details' => $details,
        ];
    }

    public function sendEmailManual(array $data, array $violationDates = []): array
    {
        $sid       = (int) $data['student_id'];
        $to        = trim((string) $data['to']);
        $subject   = (string) $data['subject'];
        $bodyInput = (string) $data['body_html'];
        $code      = (string) $data['code'];
        $variant   = (string) ($data['variant'] ?? 'default');

        $ymdRaw = (string) ($data['incident_date'] ?? '');
        $ymd    = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : '';

        $safeHtmlBody = $this->emailComposerService->normalizeBodyToHtml($bodyInput);
        $wrapped = $this->emailComposerService->renderWithEmailLayout($subject, $safeHtmlBody);

        $semester   = $this->semester ?: (string) ($this->configModel->getConfig('semester') ?? '');
        $schoolYear = $this->schoolYear ?: (string) ($this->configModel->getConfig('school_year') ?? '');

        try {
            $anyOk = false;

            $ok = $this->attendanceMailerService->send($to, $subject, $wrapped);

            $this->notificationLogService->logNotification(
                $sid,
                $code,
                $ymd,
                'email',
                $to,
                $subject,
                $ok ? 'sent' : 'failed',
                $ok ? 'OK' : 'send returned false',
                $semester,
                $schoolYear
            );

            if ($ok) {
                $anyOk = true;
            }

            $sec = $this->parentLookupService->getSecondaryParentForStudent($sid, $schoolYear);
            $to2 = trim((string) ($sec['email'] ?? ''));

            if ($to2 !== '' && strcasecmp($to2, $to) !== 0) {
                if (!$this->notificationLogService->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) {
                    $ok2 = $this->attendanceMailerService->send($to2, $subject, $wrapped);

                    $this->notificationLogService->logNotification(
                        $sid,
                        $code,
                        $ymd,
                        'email',
                        $to2,
                        $subject,
                        $ok2 ? 'sent' : 'failed',
                        $ok2 ? 'OK' : 'send returned false',
                        $semester,
                        $schoolYear
                    );

                    if ($ok2) {
                        $anyOk = true;
                    }
                }
            }

            if (!$anyOk) {
                return [
                    'success' => false,
                    'message' => 'Failed to send email.',
                    'status'  => 500,
                ];
            }

            if (method_exists($this->attendanceTrackingModel, 'markRuleAsNotified')) {
                $this->attendanceTrackingModel->markRuleAsNotified(
                    $sid,
                    $code,
                    $ymd !== '' ? $ymd : date('Y-m-d'),
                    $semester,
                    $schoolYear
                );
            }

            if (!empty($violationDates) && method_exists($this->attendanceDataModel, 'markReportedAndNotified')) {
                $this->attendanceDataModel->markReportedAndNotified(
                    $sid,
                    $violationDates,
                    $semester,
                    $schoolYear
                );
            }

            return [
                'success' => true,
                'message' => 'Email sent successfully.',
                'data'    => [
                    'student_id'    => $sid,
                    'to'            => $to,
                    'secondary_to'  => $to2 ?? null,
                    'subject'       => $subject,
                    'variant'       => $variant,
                    'incident_date' => $ymd,
                ],
            ];
        } catch (Throwable $e) {
            $this->notificationLogService->logNotification(
                $sid,
                $code,
                $ymd,
                'email',
                $to,
                $subject,
                'failed',
                $e->getMessage(),
                $semester,
                $schoolYear
            );

            return [
                'success' => false,
                'message' => 'Error: ' . $e->getMessage(),
                'status'  => 500,
            ];
        }
    }

    public function saveNotificationNote(array $data): array
    {
        $sid    = (int) $data['student_id'];
        $code   = (string) $data['code'];
        $note   = trim((string) $data['note']);
        $ymdRaw = (string) ($data['incident_date'] ?? '');
        $ymd    = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : '';

        try {
            $day = $ymd !== '' ? $ymd : date('Y-m-d');
            [$start, $end] = $this->violationRuleEngine->dayBounds($day);

            $row = $this->attendanceTrackingModel->query()
                ->where('student_id', $sid)
                ->where('semester', $this->semester)
                ->where('school_year', $this->schoolYear)
                ->where('date', '>=', $start)
                ->where('date', '<', $end)
                ->where('reason', 'like', '%' . $code . '%')
                ->orderByDesc('date')
                ->first();

            if (!$row) {
                $row = $this->attendanceTrackingModel->query()
                    ->where('student_id', $sid)
                    ->where('semester', $this->semester)
                    ->where('school_year', $this->schoolYear)
                    ->where('date', '>=', $start)
                    ->where('date', '<', $end)
                    ->orderByDesc('date')
                    ->first();
            }

            if ($row && !empty($row->id)) {
                DB::table($this->attendanceTrackingModel->getTable())
                    ->where('id', (int) $row->id)
                    ->update([
                        'notif_counter' => DB::raw('COALESCE(notif_counter,0)+1'),
                        'note'          => $note,
                        'is_notified'   => 1,
                        'updated_at'    => now(),
                    ]);
            } else {
                $this->attendanceTrackingModel->query()->create([
                    'student_id'    => $sid,
                    'date'          => $start,
                    'is_reported'   => 0,
                    'reason'        => $code,
                    'is_notified'   => 1,
                    'notif_counter' => 1,
                    'semester'      => $this->semester,
                    'school_year'   => $this->schoolYear,
                    'note'          => $note,
                    'created_at'    => now(),
                    'updated_at'    => now(),
                ]);
            }

            return [
                'success' => true,
                'message' => 'Note saved.',
            ];
        } catch (Throwable $e) {
            return [
                'success' => false,
                'message' => 'Failed to save note: ' . $e->getMessage(),
                'status'  => 500,
            ];
        }
    }
}