<?php
declare(strict_types=1);

namespace App\Services;

use App\Core\Database;
use App\Models\CronModel;
use App\Models\User;
use Throwable;

final class CronService
{
    public static function runSubmissionDeadlineReminders(bool $force = false): array
    {
        $cron = new CronModel();
        $jobId = $cron->startJob('submission_deadline_reminders');

        $notifications = 0;
        $emails = 0;

        try {
            $today = date('Y-m-d');
            $stateKey = 'submission_deadline_reminders_' . $today;

            if (!$force && $cron->getState($stateKey) === 'done') {
                $cron->finishJob($jobId, 'success', 'Already run today.', 0, 0);
                return ['notifications' => 0, 'emails' => 0];
            }

            $db = Database::getInstance();
            $stmt = $db->query("
                SELECT c.id, c.title_ar, c.title_en, c.submission_deadline,
                       u.id AS author_id, u.first_name, u.last_name, u.email, u.preferred_lang
                FROM conferences c
                INNER JOIN users u ON u.is_active = 1
                INNER JOIN roles r ON r.id = u.role_id AND r.code = 'author'
                WHERE c.is_active = 1
                  AND c.submission_deadline IS NOT NULL
                  AND DATEDIFF(c.submission_deadline, CURDATE()) BETWEEN 0 AND 3
            ");
            $rows = $stmt->fetchAll();

            foreach ($rows as $row) {
                $user = [
                    'id' => (int) $row['author_id'],
                    'first_name' => $row['first_name'],
                    'last_name' => $row['last_name'],
                    'email' => $row['email'],
                    'preferred_lang' => $row['preferred_lang'] ?? 'en',
                ];

                NotificationService::notifyAndEmail(
                    $user,
                    'submission_deadline_reminder',
                    [
                        'user_name' => trim((string) $row['first_name'] . ' ' . (string) $row['last_name']),
                        'conference_title' => (($row['preferred_lang'] ?? 'en') === 'ar') ? (string) $row['title_ar'] : (string) $row['title_en'],
                        'deadline_date' => (string) $row['submission_deadline'],
                    ],
                    'submission_deadline_reminder',
                    'conferences',
                    (int) $row['id']
                );
                $notifications++;
                if (!empty($row['email'])) {
                    $emails++;
                }
            }

            $cron->setState($stateKey, 'done');
            $cron->finishJob($jobId, 'success', 'Submission deadline reminders completed.', $notifications, $emails);

            return ['notifications' => $notifications, 'emails' => $emails];
        } catch (Throwable $e) {
            $cron->finishJob($jobId, 'failed', $e->getMessage(), $notifications, $emails);
            return ['notifications' => $notifications, 'emails' => $emails];
        }
    }

    public static function runReviewDueReminders(bool $force = false): array
    {
        $cron = new CronModel();
        $jobId = $cron->startJob('review_due_reminders');

        $notifications = 0;
        $emails = 0;

        try {
            $today = date('Y-m-d');
            $stateKey = 'review_due_reminders_' . $today;

            if (!$force && $cron->getState($stateKey) === 'done') {
                $cron->finishJob($jobId, 'success', 'Already run today.', 0, 0);
                return ['notifications' => 0, 'emails' => 0];
            }

            $db = Database::getInstance();
            $stmt = $db->query("
                SELECT ra.id AS assignment_id, ra.due_date, ra.status,
                       s.id AS submission_id, s.submission_no, s.title AS submission_title,
                       u.id AS reviewer_id, u.first_name, u.last_name, u.email, u.preferred_lang
                FROM review_assignments ra
                INNER JOIN submissions s ON s.id = ra.submission_id
                INNER JOIN users u ON u.id = ra.reviewer_id
                WHERE ra.due_date IS NOT NULL
                  AND ra.status IN ('assigned','accepted','overdue')
                  AND DATEDIFF(ra.due_date, CURDATE()) BETWEEN 0 AND 2
            ");
            $rows = $stmt->fetchAll();

            foreach ($rows as $row) {
                $user = [
                    'id' => (int) $row['reviewer_id'],
                    'first_name' => $row['first_name'],
                    'last_name' => $row['last_name'],
                    'email' => $row['email'],
                    'preferred_lang' => $row['preferred_lang'] ?? 'en',
                ];

                NotificationService::notifyAndEmail(
                    $user,
                    'review_due_reminder',
                    [
                        'user_name' => trim((string) $row['first_name'] . ' ' . (string) $row['last_name']),
                        'submission_no' => (string) $row['submission_no'],
                        'submission_title' => (string) $row['submission_title'],
                        'due_date' => (string) $row['due_date'],
                    ],
                    'review_due_reminder',
                    'review_assignments',
                    (int) $row['assignment_id']
                );
                $notifications++;
                if (!empty($row['email'])) {
                    $emails++;
                }
            }

            $overdueStmt = $db->query("
                SELECT ra.id AS assignment_id, ra.due_date,
                       s.id AS submission_id, s.submission_no, s.title AS submission_title,
                       u.id AS reviewer_id, u.first_name, u.last_name, u.email, u.preferred_lang
                FROM review_assignments ra
                INNER JOIN submissions s ON s.id = ra.submission_id
                INNER JOIN users u ON u.id = ra.reviewer_id
                WHERE ra.due_date IS NOT NULL
                  AND ra.status IN ('assigned','accepted','overdue')
                  AND ra.due_date < CURDATE()
            ");
            $overdueRows = $overdueStmt->fetchAll();

            foreach ($overdueRows as $row) {
                $user = [
                    'id' => (int) $row['reviewer_id'],
                    'first_name' => $row['first_name'],
                    'last_name' => $row['last_name'],
                    'email' => $row['email'],
                    'preferred_lang' => $row['preferred_lang'] ?? 'en',
                ];

                NotificationService::notifyAndEmail(
                    $user,
                    'review_overdue_reminder',
                    [
                        'user_name' => trim((string) $row['first_name'] . ' ' . (string) $row['last_name']),
                        'submission_no' => (string) $row['submission_no'],
                        'submission_title' => (string) $row['submission_title'],
                        'due_date' => (string) $row['due_date'],
                    ],
                    'review_overdue_reminder',
                    'review_assignments',
                    (int) $row['assignment_id']
                );
                $notifications++;
                if (!empty($row['email'])) {
                    $emails++;
                }
            }

            $cron->setState($stateKey, 'done');
            $cron->finishJob($jobId, 'success', 'Review reminders completed.', $notifications, $emails);

            return ['notifications' => $notifications, 'emails' => $emails];
        } catch (Throwable $e) {
            $cron->finishJob($jobId, 'failed', $e->getMessage(), $notifications, $emails);
            return ['notifications' => $notifications, 'emails' => $emails];
        }
    }

    public static function runDecisionPendingReminders(bool $force = false): array
    {
        $cron = new CronModel();
        $jobId = $cron->startJob('decision_pending_reminders');

        $notifications = 0;
        $emails = 0;

        try {
            $today = date('Y-m-d');
            $stateKey = 'decision_pending_reminders_' . $today;

            if (!$force && $cron->getState($stateKey) === 'done') {
                $cron->finishJob($jobId, 'success', 'Already run today.', 0, 0);
                return ['notifications' => 0, 'emails' => 0];
            }

            $db = Database::getInstance();
            $stmt = $db->query("
                SELECT s.id AS submission_id, s.submission_no, s.title AS submission_title,
                       COUNT(r.id) AS reviews_count
                FROM submissions s
                INNER JOIN review_assignments ra ON ra.submission_id = s.id AND ra.status = 'completed'
                INNER JOIN reviews r ON r.review_assignment_id = ra.id
                LEFT JOIN decisions d ON d.submission_id = s.id
                WHERE d.id IS NULL
                GROUP BY s.id, s.submission_no, s.title
                HAVING COUNT(r.id) >= 2
            ");
            $rows = $stmt->fetchAll();

            $chairs = (new User())->conferenceChairs();

            foreach ($rows as $row) {
                foreach ($chairs as $chair) {
                    NotificationService::notifyAndEmail(
                        $chair,
                        'decision_pending_reminder',
                        [
                            'user_name' => trim((string) $chair['first_name'] . ' ' . (string) $chair['last_name']),
                            'submission_no' => (string) $row['submission_no'],
                            'submission_title' => (string) $row['submission_title'],
                            'reviews_count' => (string) $row['reviews_count'],
                        ],
                        'decision_pending_reminder',
                        'submissions',
                        (int) $row['submission_id']
                    );
                    $notifications++;
                    if (!empty($chair['email'])) {
                        $emails++;
                    }
                }
            }

            $cron->setState($stateKey, 'done');
            $cron->finishJob($jobId, 'success', 'Decision reminders completed.', $notifications, $emails);

            return ['notifications' => $notifications, 'emails' => $emails];
        } catch (Throwable $e) {
            $cron->finishJob($jobId, 'failed', $e->getMessage(), $notifications, $emails);
            return ['notifications' => $notifications, 'emails' => $emails];
        }
    }

    public static function runCameraReadyReminders(bool $force = false): array
    {
        $cron = new CronModel();
        $jobId = $cron->startJob('camera_ready_reminders');

        $notifications = 0;
        $emails = 0;

        try {
            $today = date('Y-m-d');
            $stateKey = 'camera_ready_reminders_' . $today;

            if (!$force && $cron->getState($stateKey) === 'done') {
                $cron->finishJob($jobId, 'success', 'Already run today.', 0, 0);
                return ['notifications' => 0, 'emails' => 0];
            }

            $db = Database::getInstance();
            $stmt = $db->query("
                SELECT s.id AS submission_id, s.submission_no, s.title AS submission_title,
                       u.id AS author_id, u.first_name, u.last_name, u.email, u.preferred_lang
                FROM submissions s
                INNER JOIN users u ON u.id = s.author_id
                LEFT JOIN proceedings p ON p.paper_id = s.id
                WHERE s.status = 'accepted'
                  AND (p.id IS NULL OR p.camera_ready_path IS NULL OR p.camera_ready_path = '')
            ");
            $rows = $stmt->fetchAll();

            foreach ($rows as $row) {
                $user = [
                    'id' => (int) $row['author_id'],
                    'first_name' => $row['first_name'],
                    'last_name' => $row['last_name'],
                    'email' => $row['email'],
                    'preferred_lang' => $row['preferred_lang'] ?? 'en',
                ];

                NotificationService::notifyAndEmail(
                    $user,
                    'camera_ready_reminder',
                    [
                        'user_name' => trim((string) $row['first_name'] . ' ' . (string) $row['last_name']),
                        'submission_no' => (string) $row['submission_no'],
                        'submission_title' => (string) $row['submission_title'],
                    ],
                    'camera_ready_reminder',
                    'submissions',
                    (int) $row['submission_id']
                );
                $notifications++;
                if (!empty($row['email'])) {
                    $emails++;
                }
            }

            $cron->setState($stateKey, 'done');
            $cron->finishJob($jobId, 'success', 'Camera-ready reminders completed.', $notifications, $emails);

            return ['notifications' => $notifications, 'emails' => $emails];
        } catch (Throwable $e) {
            $cron->finishJob($jobId, 'failed', $e->getMessage(), $notifications, $emails);
            return ['notifications' => $notifications, 'emails' => $emails];
        }
    }

    public static function runAll(bool $force = false): array
    {
        return [
            'submission_deadline_reminders' => self::runSubmissionDeadlineReminders($force),
            'review_due_reminders' => self::runReviewDueReminders($force),
            'decision_pending_reminders' => self::runDecisionPendingReminders($force),
            'camera_ready_reminders' => self::runCameraReadyReminders($force),
        ];
    }
}
