<?php
declare(strict_types=1);

namespace App\Modules\Notifications\Services;

use App\Core\App;
use App\Core\Logger;
use App\Modules\Notifications\Models\NotificationTrigger;
use App\Modules\Notifications\Models\SmsTemplate;

/**
 * Cron-driven notification checks.
 * These methods are called by the NotificationCronJob to check for time-based triggers.
 */
final class CronNotificationService
{
    /**
     * Check for players with medical certificates expiring soon.
     * Schedules notifications at 7 days, 3 days, and on expiry day.
     */
    public static function checkMedicalExpiry(): array
    {
        $db = App::getInstance()->db();
        $today = date('Y-m-d');
        $processed = 0;

        $checkpoints = [
            ['days' => 7, 'trigger' => 'medical_expiry_7d'],
            ['days' => 3, 'trigger' => 'medical_expiry_3d'],
            ['days' => 0, 'trigger' => 'medical_expiry_today'],
        ];

        foreach ($checkpoints as $checkpoint) {
            $targetDate = date('Y-m-d', strtotime("+{$checkpoint['days']} days"));
            $triggerCode = $checkpoint['trigger'];

            $trigger = NotificationTrigger::findByCode($triggerCode);
            if (!$trigger || !$trigger['is_active']) {
                continue;
            }

            $players = $db->select("
                SELECT p.id AS player_id, p.full_name_ar, p.phone, p.guardian_phone,
                       p.medical_expiry_date
                FROM players p
                WHERE p.is_archived = 0
                  AND p.medical_expiry_date = ?
                  AND p.medical_status IN ('fit', 'conditional')
            ", [$targetDate]);

            foreach ($players as $player) {
                $phone = $player['phone'] ?: $player['guardian_phone'];
                if (empty($phone)) {
                    continue;
                }

                $templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
                $message = $templateId
                    ? NotificationTriggerService::renderMessage($templateId, [
                        'player_name'  => $player['full_name_ar'],
                        'expiry_date'  => $player['medical_expiry_date'],
                        'days_remaining' => $checkpoint['days'],
                    ])
                    : null;

                if (empty($message)) {
                    continue;
                }

                $recipientType = !empty($player['guardian_phone']) && $phone === $player['guardian_phone']
                    ? 'parent' : 'player';

                NotificationScheduler::scheduleReminder(
                    $triggerCode,
                    $recipientType,
                    (int) $player['player_id'],
                    $phone,
                    $message,
                    $today . ' 09:00:00',
                    [
                        'player_id'    => (int) $player['player_id'],
                        'expiry_date'  => $player['medical_expiry_date'],
                        'checkpoint'   => $checkpoint['days'] . 'd',
                    ]
                );
                $processed++;
            }
        }

        Logger::info("CronNotificationService::checkMedicalExpiry: {$processed} notifications scheduled");
        return ['processed' => $processed];
    }

    /**
     * Check for activity subscriptions with payments due soon.
     * Checkpoints: 5 days before, on due date, 1 day overdue.
     */
    public static function checkSubscriptionPaymentDue(): array
    {
        $db = App::getInstance()->db();
        $today = date('Y-m-d');
        $processed = 0;

        $checkpoints = [
            ['days' => 5,  'trigger' => 'subscription_payment_5d', 'compare' => 'future'],
            ['days' => 0,  'trigger' => 'subscription_payment_today', 'compare' => 'today'],
            ['days' => -1, 'trigger' => 'subscription_payment_overdue', 'compare' => 'past'],
        ];

        foreach ($checkpoints as $checkpoint) {
            $targetDate = date('Y-m-d', strtotime("{$checkpoint['days']} days"));
            $triggerCode = $checkpoint['trigger'];

            $trigger = NotificationTrigger::findByCode($triggerCode);
            if (!$trigger || !$trigger['is_active']) {
                continue;
            }

            $subscriptions = $db->select("
                SELECT asub.id AS subscription_id, asub.player_id, asub.next_payment_date,
                       asub.amount_per_period, p.full_name_ar AS player_name,
                       p.phone, p.guardian_phone,
                       a.name_ar AS activity_name
                FROM activity_subscriptions asub
                JOIN players p ON p.id = asub.player_id
                JOIN activities a ON a.id = asub.activity_id
                WHERE asub.status = 'active'
                  AND asub.next_payment_date = ?
                  AND p.is_archived = 0
            ", [$targetDate]);

            foreach ($subscriptions as $sub) {
                $phone = $sub['phone'] ?: $sub['guardian_phone'];
                if (empty($phone)) {
                    continue;
                }

                $templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
                $message = $templateId
                    ? NotificationTriggerService::renderMessage($templateId, [
                        'player_name'   => $sub['player_name'],
                        'activity_name' => $sub['activity_name'],
                        'amount'        => $sub['amount_per_period'],
                        'due_date'      => $sub['next_payment_date'],
                    ])
                    : null;

                if (empty($message)) {
                    continue;
                }

                $recipientType = !empty($sub['guardian_phone']) && $phone === $sub['guardian_phone']
                    ? 'parent' : 'player';

                NotificationScheduler::scheduleReminder(
                    $triggerCode,
                    $recipientType,
                    (int) $sub['player_id'],
                    $phone,
                    $message,
                    $today . ' 10:00:00',
                    [
                        'subscription_id' => (int) $sub['subscription_id'],
                        'player_id'       => (int) $sub['player_id'],
                        'due_date'        => $sub['next_payment_date'],
                    ]
                );
                $processed++;
            }
        }

        Logger::info("CronNotificationService::checkSubscriptionPaymentDue: {$processed} notifications scheduled");
        return ['processed' => $processed];
    }

    /**
     * Check for confirmed reservations happening tomorrow and send reminders.
     */
    public static function checkReservationReminders(): array
    {
        $db = App::getInstance()->db();
        $tomorrow = date('Y-m-d', strtotime('+1 day'));
        $today = date('Y-m-d');
        $processed = 0;

        $triggerCode = 'reservation_reminder';
        $trigger = NotificationTrigger::findByCode($triggerCode);
        if (!$trigger || !$trigger['is_active']) {
            return ['processed' => 0];
        }

        $reservations = $db->select("
            SELECT r.id AS reservation_id, r.reservation_number, r.reservation_date,
                   r.start_time, r.end_time, r.booker_name, r.booker_phone,
                   r.player_id, r.member_id,
                   f.name_ar AS facility_name
            FROM reservations r
            JOIN facilities f ON f.id = r.facility_id
            WHERE r.reservation_date = ?
              AND r.status = 'confirmed'
        ", [$tomorrow]);

        foreach ($reservations as $res) {
            $phone = $res['booker_phone'];
            if (!$phone && $res['player_id']) {
                $player = $db->selectOne("SELECT phone FROM players WHERE id = ?", [(int) $res['player_id']]);
                $phone = $player['phone'] ?? null;
            }
            if (!$phone && $res['member_id']) {
                $member = $db->selectOne("SELECT phone_mobile FROM members WHERE id = ?", [(int) $res['member_id']]);
                $phone = $member['phone_mobile'] ?? null;
            }

            if (empty($phone)) {
                continue;
            }

            $templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
            $message = $templateId
                ? NotificationTriggerService::renderMessage($templateId, [
                    'booker_name'    => $res['booker_name'] ?? '',
                    'facility_name'  => $res['facility_name'],
                    'date'           => $res['reservation_date'],
                    'start_time'     => $res['start_time'],
                    'end_time'       => $res['end_time'],
                    'reservation_number' => $res['reservation_number'],
                ])
                : null;

            if (empty($message)) {
                continue;
            }

            $recipientId = (int) ($res['member_id'] ?? $res['player_id'] ?? $res['reservation_id']);
            NotificationScheduler::scheduleReminder(
                $triggerCode,
                'booker',
                $recipientId,
                $phone,
                $message,
                $today . ' 18:00:00',
                [
                    'reservation_id' => (int) $res['reservation_id'],
                    'date'           => $res['reservation_date'],
                ]
            );
            $processed++;
        }

        Logger::info("CronNotificationService::checkReservationReminders: {$processed} reminders for {$tomorrow}");
        return ['processed' => $processed];
    }

    /**
     * Check for memberships expiring in 30 days and 7 days.
     */
    public static function checkMembershipRenewal(): array
    {
        $db = App::getInstance()->db();
        $today = date('Y-m-d');
        $processed = 0;

        $checkpoints = [
            ['days' => 30, 'trigger' => 'membership_renewal_30d'],
            ['days' => 7,  'trigger' => 'membership_renewal_7d'],
        ];

        foreach ($checkpoints as $checkpoint) {
            $targetDate = date('Y-m-d', strtotime("+{$checkpoint['days']} days"));
            $triggerCode = $checkpoint['trigger'];

            $trigger = NotificationTrigger::findByCode($triggerCode);
            if (!$trigger || !$trigger['is_active']) {
                continue;
            }

            $members = $db->select("
                SELECT m.id AS member_id, m.full_name_ar, m.phone_mobile,
                       m.membership_end_date, mt.name_ar AS membership_type
                FROM members m
                LEFT JOIN membership_types mt ON mt.id = m.membership_type_id
                WHERE m.is_archived = 0
                  AND m.status = 'active'
                  AND m.membership_end_date = ?
                  AND m.phone_mobile IS NOT NULL
                  AND m.phone_mobile != ''
            ", [$targetDate]);

            foreach ($members as $member) {
                $templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
                $message = $templateId
                    ? NotificationTriggerService::renderMessage($templateId, [
                        'member_name'     => $member['full_name_ar'],
                        'membership_type' => $member['membership_type'] ?? '',
                        'expiry_date'     => $member['membership_end_date'],
                        'days_remaining'  => $checkpoint['days'],
                    ])
                    : null;

                if (empty($message)) {
                    continue;
                }

                NotificationScheduler::scheduleReminder(
                    $triggerCode,
                    'member',
                    (int) $member['member_id'],
                    $member['phone_mobile'],
                    $message,
                    $today . ' 10:00:00',
                    [
                        'member_id'   => (int) $member['member_id'],
                        'expiry_date' => $member['membership_end_date'],
                    ]
                );
                $processed++;
            }
        }

        Logger::info("CronNotificationService::checkMembershipRenewal: {$processed} notifications scheduled");
        return ['processed' => $processed];
    }

    /**
     * Calculate monthly coach performance metrics.
     * Dispatches a summary notification to each coach with their stats.
     */
    public static function calculateCoachMetrics(): array
    {
        $db = App::getInstance()->db();
        $processed = 0;

        $triggerCode = 'coach_monthly_metrics';
        $trigger = NotificationTrigger::findByCode($triggerCode);
        if (!$trigger || !$trigger['is_active']) {
            return ['processed' => 0];
        }

        $firstDayOfMonth = date('Y-m-01');
        $lastDayOfMonth = date('Y-m-t');

        $coaches = $db->select("
            SELECT c.id AS coach_id, c.full_name_ar, c.phone
            FROM coaches c
            WHERE c.is_archived = 0
              AND c.phone IS NOT NULL
              AND c.phone != ''
        ");

        foreach ($coaches as $coach) {
            // Count sessions conducted this month
            $sessionCount = $db->selectOne("
                SELECT COUNT(*) AS cnt FROM sessions
                WHERE coach_id = ? AND session_date BETWEEN ? AND ? AND status = 'completed'
            ", [(int) $coach['coach_id'], $firstDayOfMonth, $lastDayOfMonth]);

            // Count unique players trained
            $playerCount = $db->selectOne("
                SELECT COUNT(DISTINCT sa.player_id) AS cnt
                FROM session_attendance sa
                JOIN sessions s ON s.id = sa.session_id
                WHERE s.coach_id = ? AND s.session_date BETWEEN ? AND ?
                  AND sa.status = 'present'
            ", [(int) $coach['coach_id'], $firstDayOfMonth, $lastDayOfMonth]);

            $sessions = (int) ($sessionCount['cnt'] ?? 0);
            $players = (int) ($playerCount['cnt'] ?? 0);

            if ($sessions === 0) {
                continue; // Skip coaches with no activity this month
            }

            $templateId = $trigger['template_id'] ? (int) $trigger['template_id'] : null;
            $message = $templateId
                ? NotificationTriggerService::renderMessage($templateId, [
                    'coach_name'    => $coach['full_name_ar'],
                    'month'         => date('m/Y'),
                    'session_count' => (string) $sessions,
                    'player_count'  => (string) $players,
                ])
                : null;

            if (empty($message)) {
                continue;
            }

            NotificationScheduler::scheduleReminder(
                $triggerCode,
                'coach',
                (int) $coach['coach_id'],
                $coach['phone'],
                $message,
                date('Y-m-d') . ' 12:00:00',
                [
                    'coach_id'      => (int) $coach['coach_id'],
                    'month'         => date('Y-m'),
                    'session_count' => $sessions,
                    'player_count'  => $players,
                ]
            );
            $processed++;
        }

        Logger::info("CronNotificationService::calculateCoachMetrics: {$processed} coach metrics sent");
        return ['processed' => $processed];
    }
}
