<?php
declare(strict_types=1);

namespace App\Modules\Notifications\Services;

use App\Core\App;
use App\Core\Logger;
use App\Modules\Notifications\Models\ScheduledNotification;

final class NotificationScheduler
{
    /**
     * Schedule a notification for future delivery.
     */
    public static function scheduleReminder(
        string $triggerCode,
        string $recipientType,
        int $recipientId,
        string $phone,
        string $message,
        string $scheduledAt,
        array $context = []
    ): int {
        // Deduplicate: don't schedule if same trigger+recipient+date already exists
        $alreadyExists = ScheduledNotification::existsForRecipient(
            $triggerCode,
            $recipientType,
            $recipientId,
            date('Y-m-d', strtotime($scheduledAt))
        );
        if ($alreadyExists) {
            return 0;
        }

        $db = App::getInstance()->db();
        return $db->insert('scheduled_notifications', [
            'trigger_code'    => $triggerCode,
            'recipient_type'  => $recipientType,
            'recipient_id'    => $recipientId,
            'recipient_phone' => $phone,
            'message'         => $message,
            'scheduled_at'    => $scheduledAt,
            'status'          => 'pending',
            'attempts'        => 0,
            'max_attempts'    => 3,
            'context_json'    => json_encode($context, JSON_UNESCAPED_UNICODE),
            'created_at'      => date('Y-m-d H:i:s'),
            'updated_at'      => date('Y-m-d H:i:s'),
        ]);
    }

    /**
     * Process all pending notifications that are due.
     * Called by cron runner.
     */
    public static function processPendingNotifications(int $batchSize = 100): array
    {
        $pending = ScheduledNotification::getPending($batchSize);
        $results = ['sent' => 0, 'failed' => 0, 'total' => count($pending)];

        foreach ($pending as $notification) {
            $phone = $notification['recipient_phone'] ?? '';
            if ($phone === '') {
                ScheduledNotification::markFailed((int) $notification['id'], 'No phone number');
                $results['failed']++;
                continue;
            }

            try {
                $result = SmsService::send(
                    $phone,
                    $notification['message'],
                    $notification['recipient_type'] === 'member' ? (int) $notification['recipient_id'] : null
                );

                if ($result['success']) {
                    ScheduledNotification::markSent((int) $notification['id']);
                    $results['sent']++;
                } else {
                    ScheduledNotification::markFailed(
                        (int) $notification['id'],
                        $result['error'] ?? 'Unknown error'
                    );
                    $results['failed']++;
                }
            } catch (\Throwable $e) {
                ScheduledNotification::markFailed((int) $notification['id'], $e->getMessage());
                $results['failed']++;
                Logger::error("NotificationScheduler send error: {$e->getMessage()}");
            }
        }

        if ($results['total'] > 0) {
            Logger::info("NotificationScheduler processed {$results['total']}: sent={$results['sent']}, failed={$results['failed']}");
        }

        return $results;
    }

    /**
     * Cancel all pending scheduled notifications matching the trigger code and context.
     */
    public static function cancelScheduled(string $triggerCode, array $contextMatch): int
    {
        $cancelled = ScheduledNotification::cancelByContext($triggerCode, $contextMatch);
        if ($cancelled > 0) {
            Logger::info("NotificationScheduler: cancelled {$cancelled} notifications for trigger {$triggerCode}");
        }
        return $cancelled;
    }
}
