<?php

namespace App\Jobs;

use App\Models\UploadedFile;
use App\Services\ExcelImportService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

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

    public $tries = 3;
    public $timeout = 600; // 10 minutes

    /**
     * Create a new job instance.
     */
    public function __construct(
        public int $uploadedFileId,
        public int $startRow,
        public int $chunkSize,
        public array $headerMapping
    ) {
        //
    }

    /**
     * Execute the job.
     */
    public function handle(ExcelImportService $excelService): void
    {
        $uploadedFile = UploadedFile::findOrFail($this->uploadedFileId);

        try {
            // Check if file still exists
            if (!file_exists($uploadedFile->file_path)) {
                throw new \Exception("File not found: {$uploadedFile->file_path}");
            }

            // Process the chunk
            $chunkData = $excelService->processChunk(
                $uploadedFile->file_path,
                $this->startRow,
                $this->chunkSize,
                $this->headerMapping
            );

            if (empty($chunkData)) {
                // No data in this chunk, update progress and continue
                $this->updateProgress($uploadedFile);
                return;
            }

            // Batch insert the data
            $this->batchInsert($chunkData, $uploadedFile->id);

            // Update progress
            $this->updateProgress($uploadedFile);

            // Check if there are more rows to process
            $nextRow = $this->startRow + count($chunkData);
            if ($nextRow <= $uploadedFile->total_rows) {
                // Dispatch next chunk
                self::dispatch(
                    $this->uploadedFileId,
                    $nextRow,
                    $this->chunkSize,
                    $this->headerMapping
                );
            } else {
                // All chunks processed, mark as completed
                $uploadedFile->markCompleted();
            }
        } catch (\Exception $e) {
            Log::error("Error processing chunk for file {$this->uploadedFileId} at row {$this->startRow}: " . $e->getMessage());
            $uploadedFile->markFailed($e->getMessage());
            throw $e;
        }
    }

    /**
     * Batch insert records into database
     */
    protected function batchInsert(array $chunkData, int $uploadedFileId): void
    {
        $batchSize = config('excel_columns.batch_insert_size', 100);
        $batches = array_chunk($chunkData, $batchSize);

        foreach ($batches as $batch) {
            // Add uploaded_file_id and timestamps to each record
            $now = now();
            foreach ($batch as &$record) {
                $record['uploaded_file_id'] = $uploadedFileId;
                $record['created_at'] = $now;
                $record['updated_at'] = $now;
            }

            // Insert batch
            DB::table('excel_records')->insert($batch);
        }
    }

    /**
     * Update progress on uploaded file
     */
    protected function updateProgress(UploadedFile $uploadedFile): void
    {
        $processedRows = DB::table('excel_records')
            ->where('uploaded_file_id', $uploadedFile->id)
            ->count();

        $uploadedFile->updateProgress($processedRows);
    }

    /**
     * Handle a job failure.
     */
    public function failed(\Throwable $exception): void
    {
        $uploadedFile = UploadedFile::find($this->uploadedFileId);
        if ($uploadedFile) {
            $uploadedFile->markFailed($exception->getMessage());
        }
    }
}

