<?php

namespace Licenzo\Model;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

use Licenzo\Casts\MoneyCast;
use Licenzo\Framework\Database\Model;

class Invoice extends Model
{
    protected $table = 'licenzo_invoices';

    const STATUS_DRAFT = 'draft';
    const STATUS_OPEN = 'open';
    const STATUS_PAID = 'paid';
    const STATUS_VOID = 'void';
    const STATUS_UNCOLLECTIBLE = 'uncollectible';

    const COLLECTION_CHARGE_AUTOMATICALLY = 'charge_automatically';
    const COLLECTION_SEND_INVOICE = 'send_invoice';

    protected $fillable = [
        'uuid',
        'subscription_id',
        'customer_id',
        'provider',
        'provider_invoice_id',
        'invoice_number',
        'billing_cycle_no',
        'installment_index',
        'installment_total',
        'collection_method',
        'status',
        'currency',
        'subtotal',
        'tax_total',
        'total',
        'amount_due',
        'amount_paid',
        'period_start',
        'period_end',
        'due_at',
        'paid_at',
        'snapshot',
        'meta'
    ];

    protected $casts = [
        'id' => 'int',
        'subscription_id' => 'int',
        'customer_id' => 'int',
        'billing_cycle_no' => 'int',
        'installment_index' => 'int',
        'installment_total' => 'int',
        'subtotal' => MoneyCast::class,
        'tax_total' => MoneyCast::class,
        'total' => MoneyCast::class,
        'amount_due' => MoneyCast::class,
        'amount_paid' => MoneyCast::class,
        'period_start' => 'datetime',
        'period_end' => 'datetime',
        'due_at' => 'datetime',
        'paid_at' => 'datetime',
        'snapshot' => 'array',
        'meta' => 'array',
        'created_at' => 'datetime',
        'updated_at' => 'datetime'
    ];

    public function subscription()
    {
        return $this->belongsTo(Subscription::class);
    }

    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }

    public function items()
    {
        return $this->hasMany(InvoiceItem::class);
    }

    public function transactions()
    {
        return $this->hasMany(SubscriptionTransaction::class, 'invoice_id');
    }

    public function scopeDraft($query)
    {
        return $query->where('status', static::STATUS_DRAFT);
    }

    public function scopeOpen($query)
    {
        return $query->where('status', static::STATUS_OPEN);
    }

    public function scopePaid($query)
    {
        return $query->where('status', static::STATUS_PAID);
    }

    public function scopeDue($query)
    {
        return $query->where('status', static::STATUS_OPEN)
            ->whereNotNull('due_at')
            ->where('due_at', '<=', gmdate('Y-m-d H:i:s'));
    }

    public function markAsOpen(): bool
    {
        return $this->update([
            'status' => static::STATUS_OPEN
        ]);
    }

    public function markAsPaid(float $amountPaid): bool
    {
        $nextAmountPaid = (float) $this->amount_paid + $amountPaid;
        $remaining = max(0.0, (float) $this->total - $nextAmountPaid);

        return $this->update([
            'status' => static::STATUS_PAID,
            'amount_paid' => $nextAmountPaid,
            'amount_due' => $remaining,
            'paid_at' => gmdate('Y-m-d H:i:s')
        ]);
    }
}
