<?php

namespace App\Jobs;

use App\Models\Client\Client;
use App\Models\Document\DocumentType;
use App\Models\EsignDocument;
use App\Models\Solicitor\Solicitor;
use App\Services\HistoryService;
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\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

/**
 * Downloads the signed PDF for one completed Fintrixor document via the
 * authenticated API and stores it as the client's Document. The Certificate of
 * Authenticity is already appended to that signed PDF, so it is NOT downloaded or
 * stored separately. Runs in queue/console context: re-binds the tenant Solicitor
 * and stamps solicitor_id explicitly. Idempotent — skips files already stored.
 */
class DownloadSignedEsignDocumentsJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(public readonly int $esignDocumentId) {}

    public function handle(HistoryService $history): void
    {
        $document = EsignDocument::withoutGlobalScopes()
            ->with(['contractRequest.client', 'contract'])
            ->find($this->esignDocumentId);

        if (!$document) {
            Log::warning("DownloadSignedEsignDocumentsJob: esign document {$this->esignDocumentId} not found.");
            return;
        }

        $request = $document->contractRequest;
        $client  = $request?->client;
        if (!$client instanceof Client) {
            Log::warning("DownloadSignedEsignDocumentsJob: esign document {$this->esignDocumentId} has no client.");
            return;
        }

        $solicitor = Solicitor::find($document->solicitor_id);
        if ($solicitor) {
            app()->instance(Solicitor::class, $solicitor);   // re-bind tenant for the global scope
        }

        if (!$solicitor || !$solicitor->esignReady() || !$document->provider_document_id) {
            Log::warning("DownloadSignedEsignDocumentsJob: esign document {$this->esignDocumentId} not downloadable (creds/id missing).");
            return;
        }

        $apiKey       = $solicitor->esign_api_key;
        $baseUrl      = rtrim($solicitor->esign_base_url ?: config('services.esign.base_url'), '/');
        $providerId   = $document->provider_document_id;
        $contractName = $document->contract?->name ?? 'Document';
        $unslugged    = Str::of($contractName)->replace(['-', '_'], ' ')->title()->toString();
        $docType      = DocumentType::where('display_name', $unslugged)->first();

        // Idempotency: skip if we already stored this document's signed PDF.
        $signedFile = Str::slug($contractName) . '-' . $providerId . '.pdf';
        if ($client->documents()->where('file_name', $signedFile)->exists()) {
            return;
        }

        // Signed PDF (404 until completed — release to retry if not ready yet).
        $signed = Http::withToken($apiKey)->timeout(30)->get("{$baseUrl}/documents/{$providerId}/download");
        if (!$signed->successful()) {
            Log::warning("DownloadSignedEsignDocumentsJob: signed PDF not available for document {$providerId} (HTTP {$signed->status()}).");
            $this->release(60);
            return;
        }

        $signedPath = $client->getDocumentStoragePath() . $signedFile;
        Storage::put($signedPath, $signed->body());

        $client->documents()->create([
            'solicitor_id' => $document->solicitor_id,
            'user_id'      => null,
            'display_name' => "Signed {$contractName}",
            'file_name'    => $signedFile,
            'file_type'    => 'pdf',
            'file_size'    => filesize(Storage::path($signedPath)),
            'type_id'      => $docType?->id,
        ]);

        // The Certificate of Authenticity is appended to the signed PDF above, so
        // it is not downloaded or stored as a separate client document.

        $history->add($client, "Signed document received via e-signature: {$contractName}.", [
            'contract_request_id' => $request->id,
            'esign_document_id'   => $document->id,
        ]);
    }
}
