<?php

namespace App\Listeners;

use App\Models\NotificationModel;
use App\Models\UserNotificationModel;
use App\Models\UserModel;
use App\Models\ConfigurationModel;
use App\Services\EmailService;
use App\Models\InvoiceModel;
use App\Models\FamilyModel;
use App\Models\FamilyGuardianModel;
use App\Models\PromotionQueueModel;
use App\Models\ClassSectionModel;


class SchoolEventListener
{
    protected NotificationModel $notificationModel;
    protected UserNotificationModel $userNotificationModel;
    protected UserModel $userModel;
    protected array $fromSenders;
    protected $emailService;
    protected $invoiceModel;

    public function __construct()
    {
        //parent::__construct();
        //$this->SMTPPass = env('SMTP_PASS');
        $this->notificationModel = new NotificationModel();
        $this->userNotificationModel = new UserNotificationModel();
        $this->userModel = new UserModel();
        $this->emailService = new EmailService();
        $this->invoiceModel = new InvoiceModel();

        $json = env('MAIL_SENDERS', '{}');
        $decoded = json_decode($json, true);
        $this->fromSenders = is_array($decoded) ? $decoded : [];
        //$this->fromSenders = json_decode($json, true);
    }

    protected function getSenderDetails(string $key = 'general'): array
    {
        return $this->fromSenders[$key] ?? [
            'email' => env('SMTP_USER', 'no-reply@alrahmaisgl.org'),
            'name'  => 'Al Rahma Sunday School Notifications'
        ];
    }

    protected function notifyUser($userId, $title, $message, $channels = ['in_app'], $fromKey = 'general')
    {
        $notifId = $this->notificationModel->insert([
            'title' => $title,
            'message' => $message,
            'delivery_channels' => implode(',', $channels),
        ]);

        $this->userNotificationModel->insert([
            'notification_id' => $notifId,
            'user_id' => $userId,
            'is_read' => false,
        ]);

        $user = $this->userModel->find($userId);

        if (in_array('email', $channels, true) && !empty($user['email'])) {
            $ok = $this->emailService->send($user['email'], $title, $message, $fromKey);
            if (!$ok) {
                log_message('error', "notifyUser: email send failed to {$user['email']} (user_id={$userId})");
            }
        }

        if (in_array('sms', $channels, true) && !empty($user['phone'])) {
            log_message('info', "SMS to {$user['phone']}: {$message}");
        }
    }

    public function handleAdmissionUnderReview(array $data, array $studentdata)
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        $studentNames = [];
        foreach ($studentdata as $student) {
            $fn = trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? ''));
            if ($fn !== '') $fn && $studentNames[] = $fn;
        }
        $studentNameData = count($studentNames) === 1 ? $studentNames[0] : $studentNames;

        $emailData = [
            'parentName'  => $parentName,
            'studentName' => $studentNameData,
            'portalLink'  => base_url('/login'),
            'title'       => 'Admission Application Under Review', // used by layout <title>, optional
        ];

        // In-app notification (unchanged)
        $this->notifyUser(
            $data['user_id'],
            'Admission Under Review',
            'Your admission application is under review. We will notify you once it is approved.',
            ['in_app'],
            'registration'
        );

        // Render email HTML
        $emailBody = view('emails/status_admission_review', $emailData, ['saveData' => true]);
        log_message('debug', 'admission_review email body length: ' . strlen($emailBody));

        // Send via EmailService (sets HTML + alt body)
        $ok = $this->emailService->send(
            $data['email'],
            'Admission Application Under Review',
            $emailBody,
            'registration'
        );

        if ($ok) {
            log_message('info', 'Admission under review email sent to: ' . $data['email']);
        } else {
            log_message('error', 'Failed to send admission under review email to: ' . $data['email']);
        }
    }

    /** Build student name arrays (supports ['firstname','lastname'] or ['name']) */
    private function studentNamesFrom(array $studentdata): array
    {
        $names = [];
        foreach ($studentdata as $s) {
            if (!empty($s['name'])) {
                $nm = trim($s['name']);
            } else {
                $nm = trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            }
            if ($nm !== '') {
                $names[] = $nm;
            }
        }
        return $names;
    }

    /** Single string or array (like your handleAdmissionUnderReview) */
    private function studentNameData(array $studentdata)
    {
        $names = $this->studentNamesFrom($studentdata);
        return count($names) === 1 ? $names[0] : $names;
    }

    public function handlePaymentPending(array $data, array $studentdata = []): void
    {
        // Build parent name
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build a single, human-friendly studentName string even if multiple students
        $names = [];
        foreach ($studentdata as $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm !== '') $names[] = $nm;
        }
        // "A", "A and B", "A, B, and C"
        if (count($names) === 0) {
            $studentName = 'your student';
        } elseif (count($names) === 1) {
            $studentName = $names[0];
        } elseif (count($names) === 2) {
            $studentName = $names[0] . ' and ' . $names[1];
        } else {
            $last = array_pop($names);
            $studentName = implode(', ', $names) . ', and ' . $last;
        }

        // Map to the exact variable names your template expects
        $amountDue   = $data['amount']    ?? '';                         // was 'amount'
        $dueDate     = $data['due_date']  ?? '';                         // was 'due_date'
        $portalLink = $data['paymentLink'] ?? ($data['portalLink'] ?? base_url('/login'));

        // In-app notice
        $this->notifyUser(
            $data['user_id'],
            'Payment Pending',
            'Your payment is pending. Please check your email for details.',
            ['in_app'],
            'payment'
        );

        // Render using your template path and expected variable names
        $emailData = [
            'parentName'  => $parentName,
            'studentName' => $studentName,
            'amountDue'   => $amountDue,
            'dueDate'     => $dueDate,
            'portalLink' => $portalLink,
            'title'       => 'Admission Decision',
        ];

        $body = view('emails/status_payment_pending', $emailData, ['saveData' => true]);

        $this->emailService->send(
            $data['email'] ?? null,
            'Admission Decision',
            $body,
            'payment'
        );
    }


    public function handleStudentEnrolled(array $data, array $studentdata = []): void
    {
        // Build parent name
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build names (supports ['name'] or ['firstname','lastname'])
        $names = [];
        foreach ($studentdata as $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm !== '') $names[] = $nm;
        }
        $studentNameData = count($names) === 1 ? $names[0] : $names;

        // Build a details array for multi-student presentation
        $studentsDetails = [];
        foreach ($studentdata as $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm === '') continue;

            $studentsDetails[] = [
                'name'        => $nm,
                'studentId'   => $s['student_id'] ?? $s['id'] ?? '',
                'gradeLevel'  => $s['grade_level'] ?? $s['grade'] ?? '',
                'teacherName' => $s['teacher_name'] ?? $s['teacher'] ?? '',
                'startDate'   => $s['start_date'] ?? '',
            ];
        }

        // Notify in-app
        $this->notifyUser(
            $data['user_id'] ?? $data['student_id'] ?? 0,
            'Enrollment Confirmed',
            'Enrollment confirmed. Please check your email for details.',
            ['in_app'],
            'Student Enrolled'
        );

        // Single-student fallbacks from the first student if present
        $first = $studentsDetails[0] ?? null;

        // Prepare email data matching the template variable names
        $emailData = [
            'parentName'  => $parentName,
            'studentName' => $data['student_name'] ?? $studentNameData, // can be string or array
            'schoolYear'  => $data['school_year'] ?? date('Y'),
            'studentId'   => $data['student_id'] ?? ($first['studentId']   ?? ''),
            'gradeLevel'  => $data['grade_level'] ?? ($first['gradeLevel'] ?? ''),
            'teacherName' => $data['teacher_name'] ?? ($first['teacherName'] ?? ''),
            'startDate'   => $data['start_date']  ?? ($first['startDate']   ?? ''),
            'students'    => (isset($studentsDetails) && count($studentsDetails) > 1) ? $studentsDetails : null,
            'portalLink'  => base_url('/login'),
            'title'       => 'Enrollment Confirmation',
        ];

        // Render and send
        $body = view('emails/status_enrolled', $emailData, ['saveData' => true]);

        $this->emailService->send(
            $data['email'] ?? null,
            'Enrollment Confirmation',
            $body,
            'registration'
        );
    }

    public function handleWithdrawUnderReview(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build studentName as string or array (like your helper does)
        if (method_exists($this, 'studentNameData')) {
            $studentName = $this->studentNameData($studentdata);
        } else {
            // Fallback if helper not present
            $names = [];
            foreach ($studentdata as $s) {
                $nm = !empty($s['name'])
                    ? trim($s['name'])
                    : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
                if ($nm !== '') $names[] = $nm;
            }
            $studentName = count($names) === 1 ? $names[0] : (count($names) ? $names : ($data['student_name'] ?? 'your student'));
        }

        // In-app notification
        $this->notifyUser(
            $data['user_id'],
            'Withdrawal Request Received',
            'Your withdrawal request is under review. Please check your email for details.',
            ['in_app'],
            'registration'
        );

        // EXACT variable names expected by the template
        $emailData = [
            'parentName' => $parentName,
            'studentName' => $data['student_name'] ?? $studentName, // string OR array
            'portalLink' => $data['portalLink'] ?? base_url('/login'),
            'title'      => 'Withdrawal Under Review',
        ];

        $body = view('emails/status_withdraw_review', $emailData, ['saveData' => true]);

        // Instantiate EmailService explicitly (avoid $this->emailService if not a property)
        $this->emailService->send($data['email'] ?? null, 'Withdrawal Request Under Review', $body, 'registration');
    }


    public function handleRefundPending(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build studentName as string or array (compatible with other handlers/templates)
        if (method_exists($this, 'studentNamesFrom')) {
            $names = $this->studentNamesFrom($studentdata);
        } else {
            $names = [];
            foreach ($studentdata as $s) {
                $nm = !empty($s['name'])
                    ? trim($s['name'])
                    : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
                if ($nm !== '') $names[] = $nm;
            }
        }
        if (count($names) === 0) {
            $studentName = $data['student_name'] ?? 'your student';
        } elseif (count($names) === 1) {
            $studentName = $names[0];
        } else {
            $studentName = $names; // array for multi-student rendering
        }

        // In-app notification
        $this->notifyUser(
            $data['user_id'],
            'Refund Pending',
            'A refund is being processed. Please check your email for details.',
            ['in_app'],
            'payment'
        );

        // Map to EXACT variable names used in the template
        $emailData = [
            'parentName'   => $parentName,
            'studentName'  => $studentName,                   // string OR array
            'refundAmount' => $data['amount'] ?? '',          // was 'amount'
            'portalLink'   => $data['portalLink'] ?? base_url('/login'),
            'title'        => 'Refund Pending',
        ];

        $body = view('emails/status_refund_pending', $emailData, ['saveData' => true]);

        // Send
        $this->emailService->send($data['email'] ?? null, 'Refund Pending', $body, 'payment');
    }


    public function handleWithdrawn(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build student names (string for one, array for many)
        $names = [];
        foreach ($studentdata as $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm !== '') {
                $names[] = $nm;
            }
        }
        if (count($names) === 0) {
            $studentName = $data['student_name'] ?? 'your student';
        } elseif (count($names) === 1) {
            $studentName = $names[0];
        } else {
            $studentName = $names;
        }

        // Build per-student withdrawals array if individual dates are present; otherwise single $withdrawalDate
        $withdrawals = [];
        foreach ($studentdata as $idx => $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm === '') continue;

            $wd = $s['withdrawal_date'] ?? $s['date'] ?? null;
            if ($wd) {
                $withdrawals[] = [
                    'name' => $nm,
                    'withdrawalDate' => $wd,
                ];
            }
        }
        $withdrawalDate = $data['withdrawal_date'] ?? $data['date'] ?? '';

        // In-app notice
        $this->notifyUser(
            $data['user_id'],
            'Withdrawal Confirmed',
            'Your withdrawal has been completed. Please check your email for details.',
            ['in_app'],
            'registration'
        );

        // Email payload (NOTE: template path is status_withdrawn now)
        $emailData = [
            'parentName'     => $parentName,
            'studentName'    => $studentName,            // string OR array
            'withdrawalDate' => $withdrawalDate,         // single shared date (optional)
            'withdrawals'    => !empty($withdrawals) ? $withdrawals : null, // per-student rows (optional)
            'portalLink'     => $data['portalLink'] ?? base_url('/login'),
            'title'          => 'Withdrawal Confirmed',
        ];

        $body = view('emails/status_withdrawn', $emailData, ['saveData' => true]);

        // Send email (instantiate service explicitly)
        $this->emailService->send(
            $data['email'] ?? null,
            'Withdrawal Confirmed',
            $body,
            'registration'
        );
    }


    public function handleDenied(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build name list from $studentdata; support ['name'] or ['firstname','lastname']
        $names = [];
        $studentsWithReasons = [];
        foreach ($studentdata as $s) {
            $nm = !empty($s['name'])
                ? trim($s['name'])
                : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
            if ($nm === '') continue;

            $names[] = $nm;
            // keep reason if provided
            $studentsWithReasons[] = [
                'name'   => $nm,
                'reason' => $s['reason'] ?? null,
            ];
        }

        // Provide studentName as string (one) or array (many). Fallback to $data['student_name'].
        if (count($names) === 0) {
            $studentName = $data['student_name'] ?? 'your student';
        } elseif (count($names) === 1) {
            $studentName = $names[0];
        } else {
            $studentName = $names;
        }

        // In-app notification
        $this->notifyUser(
            $data['user_id'],
            'Admission Decision',
            'We’ve emailed you an update regarding your admission decision.',
            ['in_app'],
            'registration'
        );

        // Email payload matches template variable names
        $emailData = [
            'parentName' => $parentName,
            'studentName' => $studentName,              // string OR array (template handles both)
            'students'   => $studentsWithReasons ?: null, // optional reasons block
            'portalLink' => $data['portalLink'] ?? base_url('/login'),
            'title'      => 'Admission Decision',
        ];

        $emailBody = view('emails/status_denied', $emailData, ['saveData' => true]);

        // Send email
        $this->emailService->send(
            $data['email'] ?? null,
            'Admission Decision',
            $emailBody,
            'registration'
        );
    }


    public function handleWaitlist(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // Build names array from $studentdata; fall back to $data['student_name'] if needed
        if (method_exists($this, 'studentNamesFrom')) {
            $names = $this->studentNamesFrom($studentdata);
        } else {
            $names = [];
            foreach ($studentdata as $s) {
                $nm = !empty($s['name'])
                    ? trim($s['name'])
                    : trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''));
                if ($nm !== '') $names[] = $nm;
            }
        }

        // Provide string OR array for template (string when exactly one, array when multiple)
        if (count($names) === 0) {
            $studentName = $data['student_name'] ?? 'your student';
        } elseif (count($names) === 1) {
            $studentName = $names[0];
        } else {
            $studentName = $names; // array for multi-student rendering
        }

        // In-app notification
        $this->notifyUser(
            $data['user_id'],
            'Waitlist Update',
            'Your application is currently on the waitlist. Please check your email for details.',
            ['in_app'],
            'registration'
        );

        // Exact variables expected by the template
        $emailData = [
            'parentName' => $parentName,
            'studentName' => $studentName, // string OR array (template handles both)
            'portalLink' => $data['portalLink'] ?? base_url('/login'),
            'title'      => 'Waitlist Update',
        ];

        $emailBody = view('emails/status_waitlist', $emailData, ['saveData' => true]);

        // Use EmailService directly (avoid relying on a property)
        $this->emailService->send(
            $data['email'] ?? null,
            'Admission Decision',
            $emailBody,
            'registration'
        );
    }

    public function handleEnrollmentStatusChanged(array $data, array $studentdata = []): void
    {
        // $data: user_id, email, firstname, lastname, school_year, changes[], portalLink
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        $emailData = [
            'parentName'  => $parentName,
            'schoolYear'  => $data['school_year'] ?? '',
            'changes'     => $data['changes'] ?? [],
            'portalLink'  => $data['portalLink'] ?? base_url('/login'),
            'title'       => 'Enrollment Status Update',
        ];

        $summaryCount = count($emailData['changes']);
        $this->notifyUser(
            $data['user_id'],
            'Enrollment Status Updated',
            "Enrollment status updated for {$summaryCount} student(s). Check your email for details.",
            ['in_app'],
            'registration'
        );

        // If you keep a dedicated batch template:
        $emailBody = view('emails/status_enrollment_batch', $emailData, ['saveData' => true]);
        $ok = $this->emailService->send(
            $data['email'] ?? null,
            'Enrollment Status Update',
            $emailBody,
            'registration'
        );

        $ok ? log_message('info', "Batch enrollment email sent to: {$data['email']}")
            : log_message('error', "Failed to send batch enrollment email to: {$data['email']}");
    }

    /**
     * Payment receipt notifier.
     *
     * Expects $data to include (adjust to your schema as needed):
     * - user_id        (int)   Parent/user id for in-app notification
     * - email          (string)Recipient email
     * - firstname      (string)
     * - lastname       (string)
     * - school_year    (string)
     * - semester       (string)
     * - invoice_id     (int)
     * - transaction_id (string)
     * - payment_date   (string 'Y-m-d H:i:s')
     * - amount         (float)
     * - method         (string 'cash'|'check'|'card')
     * - check_number   (string|null)
     * - installment_seq(int)   nth payment number
     * - invoice_total  (float)
     * - pre_balance    (float)
     * - post_balance   (float)
     * - portalLink     (string) optional; defaults to /login
     *
     * $studentdata is optional; passed through to the view if you want
     * to list which student(s) this invoice relates to.
     */
    public function handlePaymentReceived(array $data, array $studentdata = []): void
    {
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        $fmtMoney = static fn($v) => '$' . number_format((float) $v, 2);
        $fmtDateTz = static function (?string $s): string {
            if (!$s) return '';
            $dt = new \DateTime($s, new \DateTimeZone('UTC'));
            $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
            $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
            return $dt->format('m-d-Y h:i A');
        };

        // robust transaction id resolution
        $txid = $data['transaction_id']
            ?? $data['transactionId']
            ?? $data['payment_id']
            ?? $data['id']
            ?? '';

        $methodRaw = $data['payment_method'] ?? ($data['method'] ?? '');
        $method    = $methodRaw ? ucfirst((string) $methodRaw) : '';

        // money lines
        $amountPaid   = $fmtMoney($data['amount'] ?? 0);          // payment amount
        $preBalance   = $fmtMoney($data['pre_balance'] ?? 0);
        $postBalance  = $fmtMoney($data['post_balance'] ?? 0);
        $invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);

        // discounts (optional)
        $invoiceDiscountRaw         = isset($data['invoice_discount']) ? (float)$data['invoice_discount'] : 0.0;
        $parentYearDiscountTotalRaw = isset($data['parent_year_discount_total']) ? (float)$data['parent_year_discount_total'] : 0.0;

        $emailData = [
            'title'          => 'Payment Receipt',
            'parentName'     => $parentName,
            'schoolYear'     => $data['school_year'] ?? '',
            'semester'       => $data['semester'] ?? '',
            'invoiceId'      => $data['invoice_id'] ?? null,
            'invoiceNumber'  => $data['invoice_number'] ?? null,

            // always filled now
            'transactionId'  => $txid,

            'paymentDate'    => $fmtDateTz($data['payment_date'] ?? null),
            'method'         => $method,
            'paymentMethod'  => $method,

            'amount'         => $amountPaid,
            'invoiceTotal'   => $invoiceTotal,
            'preBalance'     => $preBalance,
            'postBalance'    => $postBalance,

            'checkNumber'    => $data['check_number'] ?? null,
            'installmentSeq' => (int) ($data['installment_seq'] ?? 1),

            // present these to the view (null = hide)
            'invoiceDiscount'         => $invoiceDiscountRaw > 0 ? $fmtMoney($invoiceDiscountRaw) : null,
            'parentYearDiscountTotal' => $parentYearDiscountTotalRaw > 0 ? $fmtMoney($parentYearDiscountTotalRaw) : null,

            'portalLink'     => base_url('/login'),
            'students'       => $studentdata,
        ];

        // In-app notification
        $inAppTitle = 'Payment Received';
        $inAppMsg   = sprintf(
            'We received %s for Invoice #%s (Installment #%d). New balance: %s. Check your email for details.',
            $emailData['amount'],
            (string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
            (int) $emailData['installmentSeq'],
            $emailData['postBalance']
        );
        $this->notifyUser(
            (int) ($data['user_id'] ?? 0),
            $inAppTitle,
            $inAppMsg,
            ['in_app'],
            'payments'
        );

        // Build email body
        $emailBody = view('emails/payment_receipt', $emailData, ['saveData' => true]);

        $subject = sprintf(
            'Payment Receipt - Invoice #%s (%s) %s',
            (string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
            $emailData['amount'],
            $txid ? "[TX: {$txid}]" : ''
        );

        $to = $data['email'] ?? null;
        if ($to) {
            $ok = $this->emailService->send($to, $subject, $emailBody, 'payments');
            if ($ok) {
                log_message('info', "Payment receipt email sent to: {$to} for invoice #{$emailData['invoiceId']} (tx={$txid})");
            } else {
                log_message('error', "Failed to send payment receipt email to: {$to} for invoice #{$emailData['invoiceId']} (tx={$txid})");
            }
        } else {
            log_message('warning', "handlePaymentReceived: missing recipient email for user_id=" . ($data['user_id'] ?? 'n/a'));
        }
    }

    /**
     * Keep the same signature style as your payment handler.
     * @param array $data        (single combined payload)
     * @param array $studentdata optional; list of students under the parent
     */
    public function handleExtraCharge(array $data, array $studentdata = []): void
    {
        // formatters (copied style)
        $fmtMoney = static fn($v) => '$' . number_format((float) $v, 2);
        // Replace your formatter(s) with these two:

        $fmtFromUtc = static function (?string $s, string $fmt = 'm-d-Y h:i A'): string {
            if (!$s) return '';
            try {
                $dt = new \DateTime($s, new \DateTimeZone('UTC'));
                $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
                return $dt->format($fmt);
            } catch (\Throwable $e) {
                log_message('error', 'fmtFromUtc error: ' . $e->getMessage());
                return '';
            }
        };

        $fmtDueLocal = static function (?string $s): string {
            if (!$s) return '';
            try {
                // Pure date (Y-m-d) → show local date only
                if (strlen($s) <= 10) {
                    $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                    $dt = \DateTime::createFromFormat('Y-m-d', $s, new \DateTimeZone($tzName ?: 'UTC'));
                    return $dt ? $dt->format('m-d-Y') : '';
                }

                // If the string includes a TZ (Z or ±HH:MM), honor it then convert to NY
                if (preg_match('/(Z|[+\-]\d{2}:\d{2})$/', $s)) {
                    $dt = new \DateTime($s); // uses embedded TZ
                    $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                    $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
                    return $dt->format('m-d-Y h:i A');
                }

                // Otherwise treat as local NY datetime (no conversion)
                $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                $dt = new \DateTime($s, new \DateTimeZone($tzName ?: 'UTC'));
                return $dt->format('m-d-Y h:i A');
            } catch (\Throwable $e) {
                log_message('error', 'fmtDueLocal error: ' . $e->getMessage());
                return '';
            }
        };

        // parent name
        $parentName = trim(($data['firstname'] ?? '') . ' ' . ($data['lastname'] ?? ''));

        // presentable money/date
        $amountSigned = (float)($data['amount_signed'] ?? 0);
        $amountAbs    = (float)($data['amount_abs'] ?? abs($amountSigned));
        $preBalance   = $fmtMoney($data['pre_balance'] ?? 0);
        $postBalance  = $fmtMoney($data['post_balance'] ?? 0);
        $invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);
        $createdAt = $fmtFromUtc($data['created_at'] ?? null);
        $dueDate   = $fmtDueLocal($data['due_date'] ?? null);
        $typeLabel = (($data['charge_type'] ?? 'add') === 'add') ? 'Added charge' : 'Deducted amount';
        $amountFmt = $fmtMoney($amountSigned); // shows + or - based on sign when combined in subject/body

        // Build email data (mirrors your payment handler shape)
        $emailData = [
            'title'         => 'Account Charge Update',
            'parentName'    => $parentName,
            'schoolYear'    => $data['school_year'] ?? '',
            'semester'      => $data['semester'] ?? '',

            'invoiceId'     => $data['invoice_id'] ?? null,
            'invoiceNumber' => $data['invoice_number'] ?? null,

            'typeLabel'     => $typeLabel,
            'chargeTitle'   => $data['charge_title'] ?? '',
            'chargeDesc'    => $data['charge_desc'] ?? '',
            'chargeType'    => $data['charge_type'] ?? 'add',

            'amountSigned'  => $amountFmt,                 // "$+/-"
            'amountAbs'     => $fmtMoney($amountAbs),      // "$X.XX"
            'invoiceTotal'  => $invoiceTotal,
            'preBalance'    => $preBalance,
            'postBalance'   => $postBalance,

            'createdAt'     => $createdAt,
            'dueDate'       => $dueDate ?: null,           // null hides in view

            'portalLink'    => $data['portal_link'] ?? base_url('/login'),
            'invoiceLink'   => $data['invoice_link'] ?? null,

            'students'      => $studentdata,               // same key as your payment email
        ];

        // In-app notification (same pattern)
        $inAppTitle = 'Account Updated';
        $invLabel   = (string)($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? '');
        $inAppMsg   = sprintf(
            '%s: %s (%s). New balance: %s.',
            $typeLabel,
            $emailData['chargeTitle'],
            $emailData['amountSigned'],
            $emailData['postBalance']
        );
        $this->notifyUser(
            (int)($data['user_id'] ?? 0),
            $inAppTitle,
            $inAppMsg,
            ['in_app'],
            'billing'
        );

        // Subject mirrors your style
        $subject = sprintf(
            'Charge Update - Invoice #%s (%s)',
            $invLabel,
            $emailData['amountSigned']
        );

        $to = $data['email'] ?? null;
        if ($to) {
            $body = view('emails/extra_charge_notice', $emailData, ['saveData' => true]);
            $ok   = $this->emailService->send($to, $subject, $body, 'billing');
            if ($ok) {
                log_message('info', "Extra charge email sent to: {$to} for invoice #{$invLabel}");
            } else {
                log_message('error', "Failed to send extra charge email to: {$to} for invoice #{$invLabel}");
            }
        } else {
            log_message('warning', 'handleExtraCharge: missing recipient email for user_id=' . ($data['user_id'] ?? 'n/a'));
        }
    }


    

    /*//////////////////////////////////////////////////////////////////////////////////////////////////
////down from this point needs verification*/

    public function handleNewAccountAdded(array $userData): void
    {
        log_message('info', '🆕 New account created: ' . json_encode($userData));

        $subject = '🎉 Welcome to Al Rahma Sunday School!';
        $message = view('emails/welcome_user', ['user' => $userData], ['saveData' => true]);

        // ✅ 1. Send to the new user
        $this->emailService->send(
            $userData['email'],
            $subject,
            $message,
            'registration'
        );

        // 🛠️ 2. Send a copy to support
        $supportEmail = 'support@alrahmaisgl.org';
        $supportMessage = view('emails/support_new_account', ['user' => $userData], ['saveData' => true]);

        $this->emailService->send(
            $supportEmail,
            '🔔 New Account Created: ' . $userData['firstname'] . ' ' . $userData['lastname'],
            $supportMessage,
            'notifications' // from MAIL_SENDERS['notifications']
        );

        // 3) Ensure Family + Guardian link so Family section shows immediately
        try {
            $userId = (int)($userData['id'] ?? 0);
            if ($userId > 0) {
                $familyCode = 'FAM-' . $userId;
                $famModel   = new FamilyModel();
                $row        = $famModel->where('family_code', $familyCode)->first();
                if (!$row) {
                    $householdName = trim('Family of ' . (($userData['firstname'] ?? '') . ' ' . ($userData['lastname'] ?? '')));
                    $famModel->insert([
                        'family_code'    => $familyCode,
                        'household_name' => $householdName,
                        'address_line1'  => $userData['address_street'] ?? null,
                        'city'           => $userData['city'] ?? null,
                        'state'          => $userData['state'] ?? null,
                        'postal_code'    => $userData['zip'] ?? null,
                        'primary_phone'  => $userData['cellphone'] ?? null,
                        'is_active'      => 1,
                    ]);
                    $familyId = (int)$famModel->getInsertID();
                } else {
                    $familyId = (int)$row['id'];
                }

                if ($familyId > 0) {
                    // Insert guardian link (idempotent)
                    $fg = new FamilyGuardianModel();
                    try {
                        // Use raw query to leverage INSERT IGNORE behavior
                        $db = \Config\Database::connect();
                        $db->query(
                            "INSERT IGNORE INTO family_guardians (family_id, user_id, relation, is_primary, receive_emails, receive_sms)
                             VALUES (?, ?, 'primary', 1, 1, 0)",
                            [$familyId, $userId]
                        );
                        // Also link any existing students of this user as primary home
                        $stuRows = $db->query("SELECT id FROM students WHERE parent_id = ?", [$userId])->getResultArray();
                        foreach ($stuRows as $sr) {
                            $sid = (int)($sr['id'] ?? 0);
                            if ($sid > 0) {
                                $db->query(
                                    "INSERT IGNORE INTO family_students (family_id, student_id, is_primary_home) VALUES (?, ?, 1)",
                                    [$familyId, $sid]
                                );
                            }
                        }
                    } catch (\Throwable $e) {
                        // Fallback: upsert-like via check
                        $exists = $fg->where(['family_id' => $familyId, 'user_id' => $userId])->first();
                        if (!$exists) {
                            $fg->insert([
                                'family_id'      => $familyId,
                                'user_id'        => $userId,
                                'relation'       => 'primary',
                                'is_primary'     => 1,
                                'receive_emails' => 1,
                                'receive_sms'    => 0,
                            ]);
                        }
                    }
                }
            }
        } catch (\Throwable $e) {
            log_message('error', 'Family ensure failed for new user: ' . $e->getMessage());
        }

        log_message('info', 'handleNewAccountAdded completed for user ID ' . $userData['id']);
    }

    public function handleStudentRegistered(array $data)
    {
        log_message('info', '📥 Student registration event received: ' . json_encode($data));

        // 🛡 Validate parent block
        if (empty($data['parents']) || !is_array($data['parents'])) {
            log_message('error', 'Missing or invalid parent data in student registration payload.');
            return;
        }

        $studentFullName = $data['firstname'] . ' ' . $data['lastname'];
        // ✅ Single parent structure
        if (!empty($data['parents']['user_id'])) {
            $title = "Your child has been registered";
            $msg = "$studentFullName has been successfully registered to Al Rahma Sunday School.";

            $this->notifyUser($data['parents']['user_id'], $title, $msg, ['in_app', 'email'], 'registration');

            log_message('info', "📢 Notification sent to parent user_id: {$data['parents']['user_id']}");
        } else {
            log_message('warning', "⚠️ Parent 'user_id' missing in payload.");
        }

        // 📩 Notify admin
        $adminEmail = 'registration@alrahmaisgl.org';
        $adminMessage = view('emails/admin_student_registered', ['student' => $data]);

        $this->emailService->send(
            $adminEmail,
            "🎓 New Student Registered: $studentFullName",
            $adminMessage,
            'notifications'
        );

        log_message('info', "✅ handleStudentRegistered complete. Notifications sent for student: $studentFullName");
    }


    public function handleDeleteUnverifiedUser(array $user)
    {
        $this->notifyUser(
            $user['id'],
            'Account Deleted - Unverified',
            'Your account was deleted because it was not verified within the time limit.',
            ['email'],
            'notifications'
        );

        $configModel = new ConfigurationModel();
        $adminEmails = array_map('trim', explode(',', $configModel->getConfig('delete_email_notify')));
        $sender = $this->getSenderDetails('notifications');

        foreach ($adminEmails as $adminEmail) {
            $email = \Config\Services::email();
            // Use SMTP user as From; Reply-To from env with fallback to sender profile
            $email->setFrom(getenv('SMTP_USER'), $sender['name'] ?? 'Al Rahma Sunday School');
            $rtEmail = env('MAIL_DEFAULT_REPLY_TO') ?: ($sender['email'] ?? getenv('SMTP_USER'));
            $rtNameEnv = env('MAIL_DEFAULT_REPLY_TO_NAME');
            $rtName = $this->sanitizeReplyToName($rtNameEnv, $sender['name'] ?? 'Al Rahma Sunday School');
            $email->setReplyTo($rtEmail, $rtName);

            $email->setTo($adminEmail);
            $email->setSubject('Unverified User Deleted');
            $email->setMessage("Unverified account deleted: ID {$user['id']}, Email {$user['email']}");
            $email->send();
        }

        log_message('info', "Unverified user deleted: ID {$user['id']}, email {$user['email']}");
    }

    public function handleUserRegistered(array $user)
    {
        $this->notifyUser($user['id'], 'Welcome!', 'Thanks for registering with our school system.', ['in_app', 'email']);
    }

    public function handleUserProfileUpdated(array $user)
    {
        $this->notifyUser($user['id'], 'Profile Updated', 'Your profile information was successfully updated.', ['in_app']);
    }

    public function handleUserDeactivated(array $user)
    {
        $this->notifyUser($user['id'], 'Account Deactivated', 'Your account has been deactivated by the administrator.', ['in_app', 'email']);
    }

    public function handleScoresPosted(array $data)
    {
        foreach ($data['students'] as $student) {
            $this->notifyUser($student['id'], 'New Score Available', 'A new score has been posted.', ['in_app', 'email'], 'registration');
        }
    }

    public function handleFinalScoreReleased(array $data)
    {
        foreach ($data['students'] as $student) {
            $this->notifyUser($student['id'], 'Final Score Released', 'Your final score for the semester is now available.', ['in_app', 'email'], 'registration');
        }

        // Also prepare promotion queue for passed students (final avg >= 60)
        try {
            $db = \Config\Database::connect();
            $cfg = new ConfigurationModel();
            $classSectionModel = new ClassSectionModel();
            $promo = new PromotionQueueModel();

            $currentYear = (string) $cfg->getConfig('school_year');
            // Compute next year string "YYYY-YYYY+1"
            if (preg_match('/^(\d{4})-(\d{4})$/', $currentYear, $m)) {
                $y1 = (int)$m[1];
                $y2 = (int)$m[2];
                $nextYear = ($y1 + 1) . '-' . ($y2 + 1);
            } else {
                // Fallback: attempt to increment the first 4-digit year
                $y = (int)substr($currentYear, 0, 4);
                $nextYear = ($y + 1) . '-' . ($y + 2);
            }

            // Build final-average per student for the current year
            $qb = $db->table('students s');
            $qb->select('s.id AS student_id');
            $qb->select('sc.class_section_id');
            $qb->select('fall.semester_score AS fall_score');
            $qb->select('spring.semester_score AS spring_score');
            $qb->join('student_class sc', 'sc.student_id = s.id AND sc.school_year = ' . $db->escape($currentYear), 'left');
            $qb->join('semester_scores fall',   "fall.student_id = s.id AND fall.semester = 'fall' AND fall.school_year = " . $db->escape($currentYear), 'left');
            $qb->join('semester_scores spring', "spring.student_id = s.id AND spring.semester = 'spring' AND spring.school_year = " . $db->escape($currentYear), 'left');
            $qb->groupBy('s.id');
            $rows = $qb->get()->getResultArray();

            foreach ($rows as $r) {
                $fall   = isset($r['fall_score']) ? (float)$r['fall_score'] : null;
                $spring = isset($r['spring_score']) ? (float)$r['spring_score'] : null;
                if ($fall === null || $spring === null) continue; // need both
                $finalAvg = ($fall + $spring) / 2.0;
                if ($finalAvg < 60.0) continue; // only successful students

                $fromSection = isset($r['class_section_id']) ? (int)$r['class_section_id'] : 0;
                if ($fromSection <= 0) continue; // unable to resolve current section

                // Resolve current class_id and compute next class_id
                $fromClassId = (int) ($classSectionModel->getClassId($fromSection) ?? 0);
                if ($fromClassId <= 0) continue;
                $toClassId = $fromClassId + 1; // simple next class; adjust if needed

                // Upsert into promotion queue for next year
                $promo->upsert([
                    'student_id'             => (int)$r['student_id'],
                    'from_class_section_id'  => $fromSection,
                    'to_class_id'            => $toClassId,
                    'to_class_section_id'    => null,
                    'school_year_from'       => $currentYear,
                    'school_year_to'         => $nextYear,
                    'status'                 => 'queued',
                    'updated_by'             => (int)(session()->get('user_id') ?? 0) ?: null,
                ]);
            }
        } catch (\Throwable $e) {
            log_message('error', 'Failed to prepare promotion queue: ' . $e->getMessage());
        }
    }

    public function handleStudentMarkedAbsent(array $record)
    {
        $this->notifyUser($record['parent_id'], 'Absence Notification', $record['student_name'] . ' was absent on ' . $record['date'], ['in_app', 'email'], 'registration');
    }

    public function handleStudentMarkedLate(array $record)
    {
        $this->notifyUser($record['parent_id'], 'Late Notification', $record['student_name'] . ' was late on ' . $record['date'], ['in_app', 'email'], 'registration');
    }

    public function handlePaymentMissed(array $user)
    {
        $this->notifyUser($user['id'], 'Payment Missed', 'You have missed a scheduled payment. Please settle your balance.', ['in_app', 'email'], 'payment');
    }

    public function handleClassScheduleUpdated(array $data)
    {
        foreach ($data['students'] as $student) {
            $this->notifyUser($student['id'], 'Schedule Update', 'Your class schedule has been updated.', ['in_app'], 'notifications');
        }
    }

    public function handleNewMessageReceived(array $data)
    {
        $this->notifyUser($data['recipient_id'], 'New Message Received', 'You have a new message from ' . $data['sender_name'], ['in_app'], 'notifications');
    }

    public function handleSystemAnnouncementPosted(array $data)
    {
        $users = $this->userModel->where('role', $data['target_group'])->findAll();
        foreach ($users as $user) {
            $this->notifyUser($user['id'], $data['title'], $data['message'], ['in_app'], 'notifications');
        }
    }

    public function handleCustomNotification(array $data)
    {
        $this->notifyUser($data['user_id'], $data['title'], $data['message'], $data['channels'] ?? ['in_app'], 'notifications');
    }

    /**
     * Normalize Reply-To names to avoid exposing "No-Reply/No-Replay" placeholders.
     */
    private function sanitizeReplyToName($name, string $fallback): string
    {
        $trimmed = trim((string) $name);
        if ($trimmed === '' || preg_match('/^no[- ]?repl(?:y|ay)$/i', $trimmed)) {
            return $fallback;
        }
        return $trimmed;
    }
}


/*
    To trigger these events anywhere in your app use:
    Events::trigger('eventName', $data).

*/

/*
    Usage Examples (Anywhere in Your App) Trigger Standard Event:
    
    use App\Services\NotificationService;

    NotificationService::trigger('gradesPosted', [
        'students' => [['id' => 12], ['id' => 14]],
        'class_id' => 3
    ]);
 
 */

 /*
    Send Custom Notification to a User:
        
    NotificationService::toUser(42, 'Reminder', 'You have a meeting at 2PM.', ['in_app', 'email']);
 */

 /*
    Wherever you delete an unverified user (for example, in a cron job or user cleanup function), trigger the event like this:

    use App\Services\NotificationService;

    // After deleting the user from database
    NotificationService::trigger('delete_unverified_user', [
        'id' => $userId,
        'email' => $userEmail
    ]);
 */

 /**/
