<?php

namespace App\Jobs;

use App\Models\BulkOperationRun;
use App\Models\Policy;
use App\Services\BulkOperationService;
use App\Services\Intune\PolicySyncService;
use Filament\Notifications\Notification;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Throwable;

class BulkPolicySyncJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public int $bulkRunId) {}

    public function handle(BulkOperationService $service, PolicySyncService $syncService): void
    {
        $run = BulkOperationRun::with(['tenant', 'user'])->find($this->bulkRunId);

        if (! $run || $run->status !== 'pending') {
            return;
        }

        $service->start($run);

        try {
            $chunkSize = max(1, (int) config('tenantpilot.bulk_operations.chunk_size', 10));
            $itemCount = 0;

            $totalItems = $run->total_items ?: count($run->item_ids ?? []);
            $failureThreshold = (int) floor($totalItems / 2);

            foreach (($run->item_ids ?? []) as $policyId) {
                $itemCount++;

                try {
                    $policy = Policy::query()
                        ->whereKey($policyId)
                        ->where('tenant_id', $run->tenant_id)
                        ->first();

                    if (! $policy) {
                        $service->recordFailure($run, (string) $policyId, 'Policy not found');

                        if ($run->failed > $failureThreshold) {
                            $service->abort($run, 'Circuit breaker: more than 50% of items failed.');

                            if ($run->user) {
                                Notification::make()
                                    ->title('Bulk Sync Aborted')
                                    ->body('Circuit breaker triggered: too many failures (>50%).')
                                    ->icon('heroicon-o-exclamation-triangle')
                                    ->danger()
                                    ->sendToDatabase($run->user)
                                    ->send();
                            }

                            return;
                        }

                        continue;
                    }

                    if ($policy->ignored_at) {
                        $service->recordSkippedWithReason($run, (string) $policyId, 'Policy is ignored locally');

                        continue;
                    }

                    $syncService->syncPolicy($run->tenant, $policy);

                    $service->recordSuccess($run);
                } catch (Throwable $e) {
                    $service->recordFailure($run, (string) $policyId, $e->getMessage());

                    if ($run->failed > $failureThreshold) {
                        $service->abort($run, 'Circuit breaker: more than 50% of items failed.');

                        if ($run->user) {
                            Notification::make()
                                ->title('Bulk Sync Aborted')
                                ->body('Circuit breaker triggered: too many failures (>50%).')
                                ->icon('heroicon-o-exclamation-triangle')
                                ->danger()
                                ->sendToDatabase($run->user)
                                ->send();
                        }

                        return;
                    }
                }

                if ($itemCount % $chunkSize === 0) {
                    $run->refresh();
                }
            }

            $service->complete($run);

            if ($run->user) {
                $message = "Synced {$run->succeeded} policies";

                if ($run->skipped > 0) {
                    $message .= " ({$run->skipped} skipped)";
                }

                if ($run->failed > 0) {
                    $message .= " ({$run->failed} failed)";
                }

                $message .= '.';

                Notification::make()
                    ->title('Bulk Sync Completed')
                    ->body($message)
                    ->icon('heroicon-o-check-circle')
                    ->success()
                    ->sendToDatabase($run->user)
                    ->send();
            }
        } catch (Throwable $e) {
            $service->fail($run, $e->getMessage());

            $run->refresh();
            $run->load('user');

            if ($run->user) {
                Notification::make()
                    ->title('Bulk Sync Failed')
                    ->body($e->getMessage())
                    ->icon('heroicon-o-x-circle')
                    ->danger()
                    ->sendToDatabase($run->user)
                    ->send();
            }

            throw $e;
        }
    }
}
