<?php

namespace App\Modules\Admin\Operations\Services;

use App\Models\User;
use App\Modules\Admin\Operations\Notifications\OperationalAlertNotification;
use App\Modules\Exports\Support\ExportStatus;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

final class OperationalAnomalyService
{
    public function scanAndNotify(): int
    {
        $alerts = [];
        $alerts = array_merge($alerts, $this->detectExportRetryStorm());
        $alerts = array_merge($alerts, $this->detectRepeatedAttendanceCorrections());

        if ($alerts === []) {
            return 0;
        }

        $admins = User::query()->where('is_admin', true)->get(['id']);
        foreach ($alerts as $a) {
            foreach ($admins as $admin) {
                /** @var User $admin */
                $admin->notify(new OperationalAlertNotification(
                    type: (string) $a['type'],
                    title: (string) $a['title'],
                    body: (string) $a['body'],
                    meta: (array) ($a['meta'] ?? []),
                ));
            }
        }

        return count($alerts);
    }

    /**
     * @return list<array{type: string, title: string, body: string, meta: array<string, mixed>}>
     */
    private function detectExportRetryStorm(): array
    {
        if (! Schema::hasTable('jobs')) {
            return [];
        }
        $threshold = (int) config('operations.retry_spike_attempts_threshold', 3);
        $count = (int) DB::table('jobs')
            ->where('attempts', '>=', $threshold)
            ->where('payload', 'like', '%ExportProcessorJob%')
            ->count();
        if ($count < 1) {
            return [];
        }

        return [[
            'type' => 'ops_export_retry_spike',
            'title' => 'Export retry spike',
            'body' => 'There are '.$count.' export jobs with attempts >= '.$threshold.'.',
            'meta' => ['count' => $count, 'attempts_threshold' => $threshold],
        ]];
    }

    /**
     * @return list<array{type: string, title: string, body: string, meta: array<string, mixed>}>
     */
    private function detectRepeatedAttendanceCorrections(): array
    {
        if (! Schema::hasTable('attendance_correction_requests')) {
            return [];
        }
        $windowDays = 3;
        $cutoff = now()->subDays($windowDays);
        $top = DB::table('attendance_correction_requests')
            ->select('tenant_id', 'employee_id', DB::raw('count(*) as c'))
            ->where('created_at', '>=', $cutoff)
            ->groupBy('tenant_id', 'employee_id')
            ->having('c', '>=', 10)
            ->orderByDesc('c')
            ->limit(5)
            ->get();
        if ($top->isEmpty()) {
            return [];
        }

        return [[
            'type' => 'ops_attendance_correction_spike',
            'title' => 'Attendance correction spike',
            'body' => 'High correction volume detected in the last '.$windowDays.' days (top groups: '.$top->count().').',
            'meta' => ['window_days' => $windowDays, 'top' => $top->toArray()],
        ]];
    }
}

