<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

/**
 * @property int $id
 * @property int $client_id
 * @property string $status
 * @property string $invoice_number
 * @property string $subtotal
 * @property string $credit
 * @property string $discount
 * @property string $gateway_fee
 * @property string $overdue_fee
 * @property string $tax
 * @property string $total
 * @property string|null $tax_rate
 * @property string $taxation_type
 * @property int|null $currency_id
 * @property string|null $payment_method
 * @property string|null $used_promotions
 * @property string|null $files
 * @property string|null $reference_number
 * @property string|null $notes
 * @property string|null $due_date
 * @property string|null $paid_date
 * @property string|null $refund_date
 * @property string|null $cancel_date
 * @property string|null $capture_date
 * @property string|null $legalized_date
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 *
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice query()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCancelDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCaptureDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereClientId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCredit($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCurrencyId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereDiscount($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereDueDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereFiles($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereGatewayFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereInvoiceNumber($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereLegalizedDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereNotes($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereOverdueFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice wherePaidDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice wherePaymentMethod($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereReferenceNumber($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereRefundDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereStatus($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereSubtotal($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTax($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTaxRate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTaxationType($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTotal($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereUpdatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereUsedPromotions($value)
 *
 * @property int|null $order_id
 * @property int|null $billing_address_id
 * @property numeric $setup_fee
 * @property numeric $tax_amount
 * @property numeric $discount_amount
 * @property string $total_amount
 * @property \Illuminate\Support\Carbon|null $issued_at
 * @property numeric $grace_period_fee
 * @property numeric $redemption_fee
 * @property numeric $processing_fee
 * @property array<array-key, mixed>|null $billing_info_snapshot
 * @property array<array-key, mixed>|null $client_info_snapshot
 * @property array<array-key, mixed>|null $custom_field_values
 * @property-read \App\Models\ClientBillingAddress|null $billingAddress
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceBillingJob> $billingJobs
 * @property-read int|null $billing_jobs_count
 * @property-read \App\Models\Client|null $client
 * @property-read \App\Models\Currency|null $currency
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceItem> $items
 * @property-read int|null $items_count
 * @property-read \App\Models\Order|null $order
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientBalance> $payments
 * @property-read int|null $payments_count
 *
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice byStatus($status)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice overdue()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice paid()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice unpaid()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereBillingAddressId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereBillingInfoSnapshot($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereClientInfoSnapshot($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereCustomFieldValues($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereDiscountAmount($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereGracePeriodFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereIssuedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereOrderId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereProcessingFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereRedemptionFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereSetupFee($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTaxAmount($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice whereTotalAmount($value)
 *
 * @mixin \Eloquent
 */
class Invoice extends Model
{
    use HasFactory, Searchable, \App\Traits\SealsAdminAttributes;

    /**
     * PRC-681 — Yasal saklama (IFRS/AB): düzenlenmiş fatura hard-delete EDİLEMEZ.
     * Yalnız 'pending' (henüz düzenlenmemiş oto-taslak) silinebilir; diğer tüm
     * durumlar (unpaid/paid/overdue/cancelled/refunded/fraud) korunur. İptal
     * gerekiyorsa status=cancelled (credit/negatif-fatura ayrı — PRC-670). Bu
     * model-katmanı guard hiçbir kod yolunun (controller/cascade/gelecek feature)
     * düzenlenmiş faturayı silmesine izin vermez.
     */
    protected static function boot()
    {
        parent::boot();

        static::deleting(function (Invoice $invoice) {
            if ($invoice->status !== self::STATUS_PENDING) {
                throw new \RuntimeException(
                    "Invoice #{$invoice->id} ({$invoice->status}) is a financial record protected by legal retention (PRC-681) and cannot be deleted. Cancel it instead."
                );
            }
        });
    }

    /**
     * Admin-only attributes — emit an audit warning when filled from outside
     * a trusted (admin guard / console / unsealed-block) context. PRC-195.
     *
     * Per ticket: client_id (ownership), total_amount / subtotal /
     * setup_fee / tax_amount / discount_amount / gateway_fee / late_fee /
     * grace_period_fee / redemption_fee / processing_fee (financial
     * totals — never client-controlled), status / paid_date / refund_date /
     * cancel_date (lifecycle), payment_method, custom_field_values
     * (admin-managed), legal_invoice_* (Gib/Logo/Parasut integration data).
     *
     * Defense-in-depth: $fillable is intentionally not modified so admin
     * controllers keep working. See app/Traits/SealsAdminAttributes.php.
     */
    protected static array $sealedAdminAttributes = [
        'client_id',
        'order_id',
        'billing_address_id',
        'subtotal',
        'setup_fee',
        'tax_amount',
        'discount_amount',
        'gateway_fee',
        'total_amount',
        'credit_applied',
        'tax_rate',
        'tax_exemption_reason',
        'accounting_excluded',
        'currency_id',
        'exchange_rate',
        'status',
        'auto_pay_enabled',
        'auto_pay_attempts',
        'last_auto_pay_attempt_at',
        'paid_date',
        'refund_date',
        'cancel_date',
        'issued_at',
        'payment_method',
        'custom_field_values',
        'grace_period_fee',
        'redemption_fee',
        'processing_fee',
        'late_fee',
        'last_late_fee_applied_at',
        'billing_info_snapshot',
        'client_info_snapshot',
        'domain_lifecycle_type',
        'domain_id',
        'legal_invoice_pdf_path',
        'legal_invoice_external_id',
        'legal_invoice_number',
        'legal_invoice_issued_at',
        'refund_external_id',
        'invoice_number',
        'paid_invoice_number',
    ];

    public function toSearchableArray(): array
    {
        $this->loadMissing(['client:id,first_name,last_name', 'currency:id,prefix', 'items:id,invoice_id,description']);

        return [
            'id' => $this->id,
            'invoice_number' => $this->invoice_number,
            'reference_number' => $this->reference_number,
            'total_amount' => $this->total_amount,
            'status' => $this->status,
            'client_id' => $this->client_id,
            'client_name' => trim(($this->client->first_name ?? '') . ' ' . ($this->client->last_name ?? '')),
            'currency_prefix' => $this->currency->prefix ?? '',
            'item_descriptions' => $this->items->pluck('description')->implode(' '),
        ];
    }

    protected $fillable = [
        'client_id',
        'order_id',
        'billing_address_id',
        'brand_id',
        'status',
        'auto_pay_enabled',
        'auto_pay_attempts',
        'last_auto_pay_attempt_at',
        'invoice_number',
        'paid_invoice_number',
        'subtotal',
        'setup_fee',
        'tax_amount',
        'discount_amount',
        'gateway_fee',
        'installment_count',
        'installment_surcharge',
        'installment_payment_id',
        'total_amount',
        'credit_applied',
        'tax_rate',
        'tax_exemption_reason',
        'accounting_excluded',
        'currency_id',
        'exchange_rate',
        'payment_method',
        'files',
        'reference_number',
        'notes',
        'due_date',
        'paid_date',
        'refund_date',
        'cancel_date',
        'issued_at',
        'custom_field_values',
        'grace_period_fee',
        'redemption_fee',
        'processing_fee',
        'late_fee',
        'last_late_fee_applied_at',
        'billing_info_snapshot',
        'client_info_snapshot',
        'domain_lifecycle_type',
        'domain_id',
        'legal_invoice_pdf_path',
        'legal_invoice_external_id',
        'legal_invoice_number',
        'legal_invoice_issued_at',
        'refund_external_id',
    ];

    protected $casts = [
        'due_date' => 'datetime',
        'paid_date' => 'datetime',
        'refund_date' => 'datetime',
        'cancel_date' => 'datetime',
        'issued_at' => 'datetime',
        'legal_invoice_issued_at' => 'datetime',
        'billing_info_snapshot' => 'array',
        'client_info_snapshot' => 'array',
        'custom_field_values' => 'array',
        'subtotal' => 'decimal:2',
        'setup_fee' => 'decimal:2',
        'tax_amount' => 'decimal:2',
        'discount_amount' => 'decimal:2',
        'gateway_fee' => 'decimal:2',
        'credit_applied' => 'decimal:2',
        'installment_surcharge' => 'decimal:2',
        'tax_rate' => 'decimal:2',
        'exchange_rate' => 'decimal:8',
        'grace_period_fee' => 'decimal:2',
        'redemption_fee' => 'decimal:2',
        'processing_fee' => 'decimal:2',
        'late_fee' => 'decimal:2',
        'last_late_fee_applied_at' => 'datetime',
        'accounting_excluded' => 'boolean',
    ];

    /**
     * Status enum değerleri
     */
    const STATUS_PENDING = 'pending';

    const STATUS_UNPAID = 'unpaid';

    const STATUS_PAID = 'paid';

    const STATUS_OVERDUE = 'overdue';

    const STATUS_CANCELLED = 'cancelled';

    const STATUS_REFUNDED = 'refunded';

    const STATUS_FRAUD = 'fraud';

    const STATUS_PROFORMA = 'proforma';

    /**
     * Status seçenekleri
     */
    public static function getStatusOptions(): array
    {
        return [
            self::STATUS_PENDING => __('models.invoice_status_pending'),
            self::STATUS_UNPAID => __('models.invoice_status_unpaid'),
            self::STATUS_PAID => __('models.invoice_status_paid'),
            self::STATUS_OVERDUE => __('models.invoice_status_overdue'),
            self::STATUS_CANCELLED => __('models.invoice_status_cancelled'),
            self::STATUS_REFUNDED => __('models.invoice_status_refunded'),
            self::STATUS_FRAUD => __('models.invoice_status_fraud'),
            self::STATUS_PROFORMA => __('models.invoice_status_proforma'),
        ];
    }

    /**
     * PRC-670 — Fatura kalemleri düzenlenebilir mi?
     *
     * Finalize/kilitli statülerde (ödenmiş / iptal / iade / fraud) kalem
     * ekleme-çıkarma, yeniden sıralama ve negatif (credit-note) satır girişi
     * yasaktır — muhasebe bütünlüğü + ödenmiş tutarla uyuşmazlık riski.
     * Bu, admin `saveItems` akışının tek kilit kaynağıdır (Policy::editItems
     * buradan okur; blade düzenleme UI'ı bununla gate'lenir).
     */
    public function areItemsEditable(): bool
    {
        return ! in_array($this->status, [
            self::STATUS_PAID,
            self::STATUS_CANCELLED,
            self::STATUS_REFUNDED,
            self::STATUS_FRAUD,
        ], true);
    }

    /**
     * Müşteri ilişkisi
     */
    public function client()
    {
        // PRC-735 — müşteri soft-delete edilse de fatura (korunan kayıt) sahibini
        // gösterebilmeli; aksi halde admin fatura görünümü null-client'ta patlar.
        return $this->belongsTo(Client::class)->withTrashed();
    }

    /**
     * PRC-845 — fatura brand'i (whitelabel görünürlük). null = ana site.
     */
    public function brand()
    {
        return $this->belongsTo(Brand::class);
    }

    /**
     * Order ilişkisi
     */
    public function order()
    {
        return $this->belongsTo(Order::class);
    }

    /**
     * Billing address ilişkisi
     */
    public function billingAddress()
    {
        return $this->belongsTo(ClientBillingAddress::class, 'billing_address_id');
    }

    /**
     * Domain lifecycle relationship (for grace/redemption invoices)
     */
    public function clientDomain()
    {
        return $this->belongsTo(ClientDomain::class, 'domain_id');
    }

    /**
     * Fatura öğeleri
     *
     * PRC-670 — Kalemler `sort_order`'a göre sıralanır (araya satır ekleme +
     * sürükle-bırak). Bu tek sıralama kaynağıdır: admin düzenleme ekranı,
     * PDF ve müşteri görünümü hep aynı sırayı görür. Eşit sort_order'da `id`
     * ile stabilize edilir (legacy/ad-hoc fee satırları default 0'dır).
     */
    public function items()
    {
        return $this->hasMany(InvoiceItem::class)
            ->orderBy('sort_order')
            ->orderBy('id');
    }

    /**
     * Para birimi
     */
    public function currency()
    {
        return $this->belongsTo(Currency::class);
    }

    /**
     * Get payments for this invoice from client_balances
     */
    public function payments()
    {
        return $this->hasMany(ClientBalance::class, 'invoice_id')
            ->whereIn('reference_type', ['payment', 'invoice_payment', 'refund', 'invoice_payment_reversal']);
    }

    /**
     * Get real money transactions for this invoice
     */
    public function transactions()
    {
        return $this->hasMany(Transaction::class, 'invoice_id');
    }

    /**
     * Get successful payment entries only
     */
    public function successfulPayments()
    {
        return $this->hasMany(ClientBalance::class, 'invoice_id')
            ->where('type', 'credit')
            ->where('reference_type', 'payment');
    }

    /**
     * Get total paid amount from client_balances
     * Sums all DEBIT entries with reference_type 'invoice_payment'
     */
    public function getTotalPaidAttribute()
    {
        $payments = ClientBalance::where('invoice_id', $this->id)
            ->where('type', 'debit')
            ->where('reference_type', 'invoice_payment')
            ->sum('amount');

        $reversals = ClientBalance::where('invoice_id', $this->id)
            ->where('type', 'credit')
            ->where('reference_type', 'invoice_payment_reversal')
            ->sum('amount');

        // PRC-1104 — cüzdan kredisi (credit_applied) de bir ödemedir: faturanın
        // "ne kadar ödendi"si gateway/manual invoice_payment + uygulanan kredidir.
        // Bunu katmadan karışık (kredi+gateway) fatura remaining_amount/isFullyPaid'de
        // yanlış görünüp asla paid'e geçmiyordu. NOT: refund tavanı gateway-only
        // kalmalı → o InvoicePaymentService::getTotalPaidForInvoice ile ayrı hesaplanır
        // (kredi kart'a iade edilemez); bu accessor yalnız durum/kalan/görüntü içindir.
        $creditApplied = (float) ($this->credit_applied ?? 0);

        return max(0, $payments - $reversals) + $creditApplied;
    }

    /**
     * Get remaining amount to be paid
     */
    public function getRemainingAmountAttribute()
    {
        return max(0, $this->total_amount - $this->total_paid);
    }

    /**
     * Check if invoice is fully paid
     */
    public function isFullyPaid()
    {
        return $this->total_paid >= $this->total_amount;
    }

    /**
     * Faturalandırma işlemleri
     */
    public function billingJobs()
    {
        return $this->hasMany(InvoiceBillingJob::class);
    }

    /**
     * PRC-62 — return the snapshot JSON if present (immutable historical
     * client info), otherwise fall back to the live client. PDF + email
     * + admin views should call this instead of `$invoice->client->...`
     * to honour the snapshot contract.
     */
    public function clientInfo(): array
    {
        if (! empty($this->client_info_snapshot) && is_array($this->client_info_snapshot)) {
            return $this->client_info_snapshot;
        }
        $client = $this->client;
        if (! $client) {
            return [];
        }

        return [
            'first_name' => $client->first_name,
            'last_name' => $client->last_name,
            'name' => $client->name,
            'email' => $client->email,
            'phone' => $client->phone,
            'company_name' => $client->company_name,
            'tax_id' => $client->tax_id,
            // PRC-404 — Country table uses `a2_iso` + `common_name`.
            'country_code' => $client->country?->a2_iso,
            'country_name' => $client->country?->common_name,
            'state' => $client->state,
            'address1' => $client->address1,
            'address2' => $client->address2,
            'postal_code' => $client->postcode,
            'language' => $client->language?->a2_iso,
            'snapshot_at' => null,
        ];
    }

    /**
     * Başarılı faturalandırma işlemleri
     */
    public function successfulBillingJobs()
    {
        return $this->billingJobs()->where('status', InvoiceBillingJob::STATUS_SUCCESS);
    }

    /**
     * Başarısız faturalandırma işlemleri
     */
    public function failedBillingJobs()
    {
        return $this->billingJobs()->where('status', InvoiceBillingJob::STATUS_FAILED);
    }

    /**
     * Bekleyen faturalandırma işlemleri
     */
    public function pendingBillingJobs()
    {
        return $this->billingJobs()->where('status', InvoiceBillingJob::STATUS_PENDING);
    }

    /**
     * Scope: Belirli durumdaki faturalar
     */
    public function scopeByStatus($query, $status)
    {
        return $query->where('status', $status);
    }

    /**
     * Scope: Vadesi geçen faturalar
     */
    public function scopeOverdue($query)
    {
        return $query->where('due_date', '<', now())
            ->where('status', 'unpaid');
    }

    /**
     * Scope: Ödenmemiş faturalar
     */
    public function scopeUnpaid($query)
    {
        return $query->where('status', 'unpaid');
    }

    /**
     * Scope: Ödenmiş faturalar
     */
    public function scopePaid($query)
    {
        return $query->where('status', 'paid');
    }

    /**
     * PRC-405 — Whether this invoice uses the cumulative model (PRC-370 / M2).
     * Detection: any item has `period_start` filled. Cumulative invoices use
     * line-based late fee accounting (one fee line per overdue cycle, updated
     * monthly); legacy invoices keep the column-based rolled-up `late_fee`.
     */
    public function isCumulative(): bool
    {
        return $this->items()->whereNotNull('period_start')->exists();
    }

    /**
     * Check if billing address can be changed for this invoice
     */
    public function canChangeBillingAddress(): bool
    {
        // If invoice is paid, billing address cannot be changed
        if ($this->status === self::STATUS_PAID) {
            return false;
        }

        // Check if client data snapshot is enabled
        $snapshotEnabled = Setting::getValue('store_client_data_snapshot', true);

        if (! $snapshotEnabled) {
            // If snapshot not enabled, allow changes
            return true;
        }

        // If invoice is unpaid, check if unpaid invoices allow address change
        if ($this->status === self::STATUS_UNPAID) {
            return Setting::getValue('allow_billing_address_change_on_unpaid', false);
        }

        // For other statuses (pending, etc.), allow change
        return true;
    }

    /**
     * PRC-1097 — Amount still owed after any applied credit balance.
     * Equals total_amount when no credit was applied (credit_applied defaults to
     * 0), so routing gateway charges through this is backward-compatible; when
     * partial credit is applied it is the remainder the gateway must charge.
     */
    public function amountDue(): float
    {
        return max(0.0, round((float) $this->total_amount - (float) ($this->credit_applied ?? 0), 2));
    }

    /**
     * Resolve the effective payment gateway name for this invoice.
     *
     * For regular invoices the gateway is stored on the associated Order.
     * Plan-change (upgrade) invoices are standalone — they have no order_id —
     * so we fall back through: invoice.payment_method → first active gateway.
     */
    public function getEffectiveGatewayName(): ?string
    {
        if ($this->order?->payment_gateway_name) {
            return $this->order->payment_gateway_name;
        }

        if ($this->payment_method) {
            return $this->payment_method;
        }

        // Last resort: pick first active gateway from PaymentManager
        $allGateways = app(\App\Services\PaymentManager::class)->getAvailableGateways();
        foreach ($allGateways as $name => $info) {
            if ($info['active'] ?? false) {
                return $name;
            }
        }

        return null;
    }

    /**
     * Generate HTML table for invoice items (for email templates)
     */
    public function getItemsHtmlTable(): string
    {
        $currencySymbol = $this->currency->symbol ?? 'TRY';

        $html = '<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">';
        $html .= '<thead>';
        $html .= '<tr style="background-color: #f8f9fa; border-bottom: 2px solid #dee2e6;">';
        $html .= '<th style="padding: 12px; text-align: left; border: 1px solid #dee2e6;">'.__('models.invoice_table_description').'</th>';
        $html .= '<th style="padding: 12px; text-align: center; border: 1px solid #dee2e6;">'.__('models.invoice_table_quantity').'</th>';
        $html .= '<th style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_unit_price').'</th>';
        $html .= '<th style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_total').'</th>';
        $html .= '</tr>';
        $html .= '</thead>';
        $html .= '<tbody>';

        foreach ($this->items as $item) {
            $html .= '<tr style="border-bottom: 1px solid #dee2e6;">';
            $html .= '<td style="padding: 12px; border: 1px solid #dee2e6;">'.e($item->description).'</td>';
            $html .= '<td style="padding: 12px; text-align: center; border: 1px solid #dee2e6;">'.$item->quantity.'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($item->unit_price, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;"><strong>'.number_format($item->line_total, 2, ',', '.').' '.$currencySymbol.'</strong></td>';
            $html .= '</tr>';
        }

        $html .= '</tbody>';
        $html .= '<tfoot>';

        // Ara Toplam
        $html .= '<tr style="border-top: 2px solid #dee2e6;">';
        $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_subtotal').'</td>';
        $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;"><strong>'.number_format($this->subtotal, 2, ',', '.').' '.$currencySymbol.'</strong></td>';
        $html .= '</tr>';

        // Kurulum Ücreti (varsa)
        if ($this->setup_fee > 0) {
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_setup_fee').'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($this->setup_fee, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        // İndirim (varsa)
        if ($this->discount_amount > 0) {
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6; color: #28a745;">'.__('models.invoice_table_discount').'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6; color: #28a745;">-'.number_format($this->discount_amount, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        // Vergi (varsa)
        if ($this->tax_amount > 0) {
            $taxLabel = __('models.invoice_table_tax');
            if ($this->tax_rate > 0) {
                $taxLabel .= ' (%'.number_format($this->tax_rate, 0).')';
            }
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.$taxLabel.':</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($this->tax_amount, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        // Gateway Ücreti (varsa)
        if ($this->gateway_fee > 0) {
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_payment_processing_fee').'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($this->gateway_fee, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        // Diğer ücretler (grace_period_fee, processing_fee, redemption_fee)
        if (isset($this->grace_period_fee) && $this->grace_period_fee > 0) {
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_grace_period_fee').'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($this->grace_period_fee, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        if (isset($this->processing_fee) && $this->processing_fee > 0) {
            $html .= '<tr>';
            $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.__('models.invoice_table_processing_fee').'</td>';
            $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6;">'.number_format($this->processing_fee, 2, ',', '.').' '.$currencySymbol.'</td>';
            $html .= '</tr>';
        }

        // Genel Toplam
        $html .= '<tr style="background-color: #f8f9fa; border-top: 2px solid #dee2e6;">';
        $html .= '<td colspan="3" style="padding: 12px; text-align: right; border: 1px solid #dee2e6; font-size: 16px;"><strong>'.__('models.invoice_table_grand_total').'</strong></td>';
        $html .= '<td style="padding: 12px; text-align: right; border: 1px solid #dee2e6; font-size: 16px;"><strong>'.number_format($this->total_amount, 2, ',', '.').' '.$currencySymbol.'</strong></td>';
        $html .= '</tr>';

        $html .= '</tfoot>';
        $html .= '</table>';

        return $html;
    }
}
