<?php

namespace App\Jobs;

use App\Models\BulkOperationRun;
use App\Models\Policy;
use App\Services\BulkOperationService;
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 BulkPolicyDeleteJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(

        public int $bulkRunId

    ) {}

    public function handle(BulkOperationService $service): void
    {

        $run = BulkOperationRun::with('user')->find($this->bulkRunId);

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

            return;

        }

        $service->start($run);

        try {

            $itemCount = 0;
            $succeeded = 0;
            $failed = 0;
            $skipped = 0;
            $failures = [];

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

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

            foreach ($run->item_ids as $policyId) {

                $itemCount++;

                try {

                    $policy = Policy::find($policyId);

                    if (! $policy) {

                        $service->recordFailure($run, (string) $policyId, 'Policy not found');
                        $failed++;
                        $failures[] = [
                            'item_id' => (string) $policyId,
                            'reason' => 'Policy not found',
                            'timestamp' => now()->toIso8601String(),
                        ];

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

                            if ($run->user) {
                                Notification::make()
                                    ->title('Bulk Delete 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->recordSkipped($run);
                        $skipped++;

                        continue;

                    }

                    $policy->ignore();

                    $service->recordSuccess($run);
                    $succeeded++;

                } catch (Throwable $e) {

                    $service->recordFailure($run, (string) $policyId, $e->getMessage());
                    $failed++;
                    $failures[] = [
                        'item_id' => (string) $policyId,
                        'reason' => $e->getMessage(),
                        'timestamp' => now()->toIso8601String(),
                    ];

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

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

                        return;
                    }

                }

                // Refresh the run from database every $chunkSize items to avoid stale data

                if ($itemCount % $chunkSize === 0) {

                    $run->refresh();

                }

            }

            $service->complete($run);

            if ($succeeded > 0 || $failed > 0 || $skipped > 0) {
                $message = "Successfully deleted {$succeeded} policies";
                if ($skipped > 0) {
                    $message .= " ({$skipped} skipped)";
                }
                if ($failed > 0) {
                    $message .= " ({$failed} failed)";
                }
                $message .= '.';

                Notification::make()
                    ->title('Bulk Delete Completed')
                    ->body($message)
                    ->icon('heroicon-o-check-circle')
                    ->success()
                    ->sendToDatabase($run->user)
                    ->send();
            }

        } catch (Throwable $e) {

            $service->fail($run, $e->getMessage());

            // Reload run with user relationship
            $run->refresh();
            $run->load('user');

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

            throw $e;
        }

    }
}
