<?php
declare(strict_types=1);

namespace CronJobs;

use App\Core\Database;

class AlertProcessorJob
{
    private Database $db;
    public function __construct(Database $db) { $this->db = $db; }

    public function shouldRun(): bool
    {
        return true; // Hourly via system cron
    }

    public function run(): array
    {
        $triggered = 0;

        $rules = $this->db->select(
            "SELECT * FROM alert_rules WHERE is_active = 1"
        );

        foreach ($rules as $rule) {
            $results = $this->checkRule($rule);
            foreach ($results as $context) {
                $this->db->insert('alert_log', [
                    'alert_rule_id' => (int) $rule['id'],
                    'context_json'  => json_encode($context, JSON_UNESCAPED_UNICODE),
                    'status'        => 'sent',
                ]);
                $triggered++;
            }

            if (!empty($results)) {
                $this->db->update('alert_rules', [
                    'last_triggered_at' => date('Y-m-d H:i:s'),
                ], 'id = ?', [(int) $rule['id']]);
            }
        }

        return [
            'status'  => 'success',
            'message' => "Processed alerts: {$triggered} triggered.",
        ];
    }

    private function checkRule(array $rule): array
    {
        $config = json_decode($rule['trigger_config_json'] ?? '{}', true) ?: [];

        return match ($rule['code']) {
            'MEDICAL_CERT_EXPIRY'    => $this->checkMedicalExpiry($config),
            'CONTRACT_EXPIRY'        => $this->checkContractExpiry($config),
            'ATTENDANCE_DROPPING'    => $this->checkAttendanceDropping($config),
            'GROUP_NEAR_CAPACITY'    => $this->checkGroupCapacity($config),
            'SUBSCRIPTION_OVERDUE'   => $this->checkOverdueSubscriptions($config),
            default                  => [],
        };
    }

    private function checkMedicalExpiry(array $config): array
    {
        $days = $config['days_before'] ?? 30;
        $targetDate = date('Y-m-d', strtotime('+' . $days . ' days'));

        $rows = $this->db->select("
            SELECT p.id, p.full_name_ar, p.medical_expiry_date
            FROM players p
            WHERE p.is_archived = 0
              AND p.medical_expiry_date IS NOT NULL
              AND p.medical_expiry_date = ?
        ", [$targetDate]);

        $results = [];
        foreach ($rows as $row) {
            $alreadyLogged = $this->db->selectOne("
                SELECT id FROM alert_log
                WHERE alert_rule_id = (SELECT id FROM alert_rules WHERE code = 'MEDICAL_CERT_EXPIRY' LIMIT 1)
                  AND JSON_EXTRACT(context_json, '$.player_id') = ?
                  AND triggered_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
            ", [(int) $row['id']]);

            if (!$alreadyLogged) {
                $results[] = [
                    'player_id'   => (int) $row['id'],
                    'player_name' => $row['full_name_ar'],
                    'expiry_date' => $row['medical_expiry_date'],
                    'days_left'   => $days,
                ];
            }
        }
        return $results;
    }

    private function checkContractExpiry(array $config): array
    {
        $days = $config['days_before'] ?? 30;
        $targetDate = date('Y-m-d', strtotime('+' . $days . ' days'));

        $rows = $this->db->select("
            SELECT ac.id, ac.contract_number, ac.end_date, a.name_ar AS academy_name
            FROM academy_contracts ac
            JOIN academies a ON a.id = ac.academy_id
            WHERE ac.status = 'active' AND ac.end_date = ?
        ", [$targetDate]);

        return array_map(fn($r) => [
            'contract_id'     => (int) $r['id'],
            'contract_number' => $r['contract_number'],
            'academy_name'    => $r['academy_name'],
            'end_date'        => $r['end_date'],
        ], $rows);
    }

    private function checkAttendanceDropping(array $config): array
    {
        $threshold = $config['consecutive_absences'] ?? 3;

        $rows = $this->db->select("
            SELECT sa.player_id, p.full_name_ar,
                   COUNT(*) AS consecutive_absences
            FROM session_attendance sa
            JOIN players p ON p.id = sa.player_id
            JOIN training_sessions ts ON ts.id = sa.session_id
            WHERE sa.status = 'absent'
              AND ts.session_date >= DATE_SUB(CURDATE(), INTERVAL 14 DAY)
            GROUP BY sa.player_id
            HAVING consecutive_absences >= ?
        ", [$threshold]);

        return array_map(fn($r) => [
            'player_id'   => (int) $r['player_id'],
            'player_name' => $r['full_name_ar'],
            'absences'    => (int) $r['consecutive_absences'],
        ], $rows);
    }

    private function checkGroupCapacity(array $config): array
    {
        $threshold = $config['capacity_pct'] ?? 90;

        $rows = $this->db->select("
            SELECT id, name_ar, current_count, max_capacity,
                   ROUND((current_count / max_capacity) * 100) AS utilization_pct
            FROM training_groups
            WHERE status = 'active'
              AND max_capacity > 0
              AND ROUND((current_count / max_capacity) * 100) >= ?
              AND is_full = 0
        ", [$threshold]);

        return array_map(fn($r) => [
            'group_id'        => (int) $r['id'],
            'group_name'      => $r['name_ar'],
            'current'         => (int) $r['current_count'],
            'max'             => (int) $r['max_capacity'],
            'utilization_pct' => (int) $r['utilization_pct'],
        ], $rows);
    }

    private function checkOverdueSubscriptions(array $config): array
    {
        $daysOverdue = $config['days_overdue'] ?? 7;
        $targetDate = date('Y-m-d', strtotime('-' . $daysOverdue . ' days'));

        $rows = $this->db->select("
            SELECT s.id, s.player_id, s.total_amount, s.due_date,
                   p.full_name_ar
            FROM activity_subscriptions s
            JOIN players p ON p.id = s.player_id
            WHERE s.status = 'overdue'
              AND s.due_date = ?
        ", [$targetDate]);

        return array_map(fn($r) => [
            'subscription_id' => (int) $r['id'],
            'player_id'       => (int) $r['player_id'],
            'player_name'     => $r['full_name_ar'],
            'amount'          => (float) $r['total_amount'],
            'due_date'        => $r['due_date'],
        ], $rows);
    }
}
