<?php

namespace App\Console\Commands;

use App\Models\InvoiceBillingJob;
use App\Modules\Billing\BillingModuleFactory;
use App\Modules\Billing\BillingResponse;
use App\Services\Billing\InvoicePdfStorage;
use App\Services\Billing\LegalInvoiceFinalizer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

/**
 * PRC-890 — asenkron yasal fatura onay poll'ü.
 *
 * `submitted` durumundaki işleri sağlayıcıdan sorgular (`checkInvoiceStatus`):
 *  - approved → LegalInvoiceFinalizer::finalizeSuccess (kolon + PDF + event)
 *  - rejected → finalizeFailure (LegalInvoiceFailed)
 *  - pending  → retry_count++ ; billing_poll_max_attempts aşımında failed (sonsuz poll yok)
 * Bir faturaya yalnız bir kez yasal belge yazılır (idempotency senkron yolla ortak).
 */
class PollLegalInvoicesCommand extends Command
{
    protected $signature = 'billing:poll-legal-invoices {--limit=50 : İşlenecek maksimum iş sayısı}';

    protected $description = 'Asenkron gönderilmiş (submitted) yasal faturaların onay durumunu sorgula';

    public function handle(LegalInvoiceFinalizer $finalizer, InvoicePdfStorage $pdfStore): int
    {
        if (! setting('billing_poll_legal_invoices', false)) {
            $this->info('Yasal fatura poll kapalı (billing_poll_legal_invoices). Atlanıyor.');

            return self::SUCCESS;
        }

        $maxAttempts = (int) setting('billing_poll_max_attempts', 12);
        $limit = (int) $this->option('limit');

        $jobs = InvoiceBillingJob::where('status', InvoiceBillingJob::STATUS_SUBMITTED)
            ->with(['billingModule', 'invoice'])
            ->orderBy('created_at', 'asc')
            ->limit($limit)
            ->get();

        if ($jobs->isEmpty()) {
            $this->info('Onay bekleyen (submitted) iş yok.');

            return self::SUCCESS;
        }

        $errorCount = 0;

        foreach ($jobs as $job) {
            try {
                $this->pollJob($job, $finalizer, $pdfStore, $maxAttempts);
            } catch (\Throwable $e) {
                // checkInvoiceStatus / ağ hatası → işi submitted bırak, sonraki tur dene.
                $errorCount++;
                Log::warning('PollLegalInvoices: iş sorgulanamadı (submitted bırakıldı): '.$e->getMessage(), [
                    'job_id' => $job->id,
                    'invoice_id' => $job->invoice_id,
                ]);
            }
        }

        // Non-zero exit → cron monitoring alarm verebilir (PRC-53 deseni).
        return $errorCount > 0 ? self::FAILURE : self::SUCCESS;
    }

    protected function pollJob(
        InvoiceBillingJob $job,
        LegalInvoiceFinalizer $finalizer,
        InvoicePdfStorage $pdfStore,
        int $maxAttempts,
    ): void {
        $module = $job->billingModule;
        $invoice = $job->invoice;

        if (! $module || ! $invoice) {
            $job->update([
                'status' => InvoiceBillingJob::STATUS_FAILED,
                'error_message' => 'Missing module or invoice',
                'processed_at' => now(),
            ]);

            return;
        }

        $moduleInstance = BillingModuleFactory::createFromModel($module);
        $raw = $moduleInstance->checkInvoiceStatus((string) $job->external_id, []);
        $resp = $raw instanceof BillingResponse ? $raw : BillingResponse::fromArray((array) $raw);

        switch ($resp->status) {
            case 'approved':
                $finalizer->finalizeSuccess($job, $invoice, $resp, $pdfStore, 'PollLegalInvoices');
                break;

            case 'rejected':
                $finalizer->finalizeFailure($job, $invoice, $resp);
                break;

            case 'pending':
            default:
                $attempts = (int) $job->retry_count + 1;
                if ($attempts >= $maxAttempts) {
                    $timeout = new BillingResponse(
                        success: false,
                        message: "Yasal fatura onay poll'ü {$maxAttempts} denemede sonuçlanmadı (timeout)",
                        raw: $resp->raw,
                    );
                    $finalizer->finalizeFailure($job, $invoice, $timeout);
                } else {
                    $job->update(['retry_count' => $attempts]);
                }
                break;
        }
    }
}
