<?php

declare(strict_types=1);

final class NotificationService
{
    public static function alerts(): array
    {
        $db = DB::pdo();
        $alerts = [];
        $queries = [
            [
                'vaccines',
                'danger',
                t('notification.vaccines_overdue'),
                "SELECT COUNT(*) FROM vaccinations v JOIN animals a ON a.id=v.animal_id WHERE v.due_date IS NOT NULL AND date(v.due_date)<date('now') AND a.deleted_at IS NULL AND a.archived_at IS NULL AND lower(a.status) NOT IN ('decede','décédé','adopte','adopté')",
                '/dashboard#vaccine-deadlines',
            ],
            [
                'treatments',
                'danger',
                t('notification.treatments_overdue'),
                "SELECT COUNT(*) FROM treatments t JOIN animals a ON a.id=t.animal_id WHERE t.ongoing=1 AND t.end_date IS NOT NULL AND date(t.end_date)<date('now') AND a.deleted_at IS NULL AND a.archived_at IS NULL",
                '/dashboard#active-treatments',
            ],
            [
                'dewormings',
                'warning',
                t('notification.dewormings_due'),
                "SELECT COUNT(*) FROM dewormings d JOIN animals a ON a.id=d.animal_id WHERE d.next_due_date IS NOT NULL AND date(d.next_due_date)<=date('now','+7 day') AND a.deleted_at IS NULL AND a.archived_at IS NULL AND NOT EXISTS(SELECT 1 FROM dewormings newer WHERE newer.animal_id=d.animal_id AND date(newer.administered_on)>date(d.administered_on))",
                '/dashboard',
            ],
        ];
        foreach ($queries as [$key, $severity, $label, $sql, $url]) {
            try {
                $count = (int) $db->query($sql)->fetchColumn();
                if ($count) {
                    $alerts[] = compact('key', 'severity', 'label', 'count', 'url');
                }
            } catch (Throwable) {
            }
        }
        if (class_exists(InventoryService::class)) {
            try {
                $stock = InventoryService::alerts();
                if ($stock['low']) {
                    $alerts[] = [
                        'key' => 'inventory-low',
                        'severity' => 'warning',
                        'label' => t('notification.inventory_low'),
                        'count' => count($stock['low']),
                        'url' => '/settings/inventory',
                    ];
                }
                if ($stock['expired']) {
                    $alerts[] = [
                        'key' => 'inventory-expiry',
                        'severity' => 'danger',
                        'label' => t('notification.inventory_expiry'),
                        'count' => count($stock['expired']),
                        'url' => '/settings/inventory',
                    ];
                }
            } catch (Throwable) {
            }
        }
        if (class_exists(AgendaService::class)) {
            try {
                $due = AgendaService::due();
                if ($due) {
                    $alerts[] = [
                        'key' => 'agenda',
                        'severity' => 'warning',
                        'label' => t('notification.agenda_due'),
                        'count' => count($due),
                        'url' => '/agenda',
                    ];
                }
            } catch (Throwable) {
            }
        }
        $backups = BackupService::list();
        $days = 999;
        if (
            $backups &&
            ($date = DateTimeImmutable::createFromFormat(
                'd/m/Y H:i:s',
                (string) $backups[0]['date'],
                new DateTimeZone('Europe/Paris'),
            ))
        ) {
            $days = (int) $date->diff(new DateTimeImmutable('now', new DateTimeZone('Europe/Paris')))->format('%a');
        }
        if ($days > 7) {
            $alerts[] = [
                'key' => 'backup',
                'severity' => $days > 30 ? 'danger' : 'warning',
                'label' => t('notification.backup_old'),
                'count' => $days,
                'url' => '/settings/backups',
            ];
        }
        return $alerts;
    }
    public static function send(bool $force = false): array
    {
        if (AppSettings::get('notification_email_enabled') !== '1' && !$force) {
            return ['sent' => false, 'reason' => 'disabled'];
        }
        $recipient = AppSettings::get('notification_email_recipient') ?: AppSettings::get('association_email');
        if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
            return ['sent' => false, 'reason' => 'recipient'];
        }
        $frequency = AppSettings::get('notification_email_frequency');
        $last = AppSettings::get('notification_last_sent_at');
        if (!$force && $last !== '') {
            $elapsed = time() - (strtotime($last) ?: 0);
            $minimum = $frequency === 'daily' ? 20 * 3600 : 6 * 86400;
            if ($elapsed < $minimum) {
                return ['sent' => false, 'reason' => 'not_due'];
            }
        }
        $alerts = self::alerts();
        $association = AppSettings::get('association_name') ?: 'Globinours';
        $subject = '[' . $association . '] ' . t('notification.email_subject');
        $lines = [t('notification.email_intro', ['association' => $association]), ''];
        if (!$alerts) {
            $lines[] = t('notification.no_alert');
        } else {
            foreach ($alerts as $a) {
                $lines[] = '- ' . $a['label'] . ' : ' . $a['count'];
            }
        }
        $lines[] = '';
        $lines[] = t('notification.email_footer');
        $sent = @mail($recipient, $subject, implode("\n", $lines), 'Content-Type: text/plain; charset=UTF-8');
        if ($sent) {
            AppSettings::save(['notification_last_sent_at' => date('Y-m-d H:i:s')], Auth::id());
        }
        return ['sent' => $sent, 'reason' => $sent ? 'sent' : 'mail_failed', 'count' => count($alerts)];
    }
}
