<?php

namespace Daniv04\HaciendaPackage\Jobs;

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\Log;
use Daniv04\HaciendaPackage\Models\Receipt;
use Daniv04\HaciendaPackage\Services\Providers\ProviderFactoryService;
use Daniv04\HaciendaPackage\Exceptions\ProviderException;
use Throwable;

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

    public $tries = 3;
    public $timeout = 120;
    public $backoff = [30, 60, 90];
    public $maxExceptions = 3;

    /**
     * Create a new job instance.
     */
    public function __construct(
        public Receipt $receipt,
        public string $provider
    ) {}

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(ProviderFactoryService $providerFactoryService): void
    {
        Log::info("Starting SendReceiptToProviderJob for Receipt", [
            'receipt_id' => $this->receipt->id,
            'provider' => $this->provider
        ]);



        try {

            $providerInstance = $providerFactoryService->getProviderInstance($this->provider);
            if (!$providerInstance) {
                Log::error("Provider instance not found in SendReceiptToProviderJob", [
                    'receipt_id' => $this->receipt->id,
                    'provider' => $this->provider
                ]);
                return;
            }

            $validatedData = $this->receipt->payload->payload_json;

            $response = $providerInstance->sendDocument($validatedData, $this->receipt->consecutive_number);

            if (!$response->success) {
                Log::warning("Error sending document to provider", [
                    'receipt_id' => $this->receipt->id,
                    'provider' => $this->provider,
                    'attempt' => $this->attempts(),
                    'message' => $response->errorMessage,
                    'retriable' => $response->retriable,
                ]);

                if (!$response->retriable) {
                    $this->receipt->update(['receipt_status' => 'validation_error']);
                    Log::warning("Non-retriable error, marking as validation_error", [
                        'receipt_id' => $this->receipt->id,
                        'message' => $response->errorMessage,
                    ]);
                    return;
                }

                throw new ProviderException("Error sending document: " . $response->errorMessage);
            }

            $this->receipt->update([
                'receipt_status' => 'sent',
                'ui_key' => $response->documentKey,
                'sent_to_hacienda_at' => $response->sentAt,
                'signed_xml' => $response->signedXml,
            ]);

            Log::info("Successfully sent document to provider", [
                'receipt_id' => $this->receipt->id,
                'ui_key' => $response->documentKey,
                'provider' => $this->provider,
            ]);
        } catch (\Exception $e) {
            Log::error('Error in SendReceiptToProviderJob', [
                'receipt_id' => $this->receipt->id,
                'attempt' => $this->attempts(),
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            throw $e;
        }
    }

    public function failed(\Throwable $exception): void
    {
        Log::error('SendReceiptToProviderJob failed after maximum attempts', [
            'receipt_id' => $this->receipt->id,
            'attempts' => $this->attempts(),
            'error' => $exception->getMessage(),
            'trace' => $exception->getTraceAsString()
        ]);

        $this->receipt->update([
            'receipt_status' => 'failed',
        ]);
    }
}
