<?php

declare(strict_types=1);

namespace common\models;

use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;

/**
 * Invoice ActiveRecord model.
 *
 * @property int         $id
 * @property string      $invoice_number
 * @property int         $customer_id
 * @property int|null    $customer_plan_id
 * @property string      $invoice_date
 * @property string|null $due_date
 * @property float       $subtotal
 * @property float       $gst_rate
 * @property float       $gst_amount
 * @property float       $discount_amount
 * @property float       $total_amount
 * @property float       $paid_amount
 * @property string      $status  unpaid|partial|paid|cancelled
 * @property string|null $notes
 * @property int|null    $created_by
 * @property int         $created_at
 * @property int         $updated_at
 *
 * @property Customer       $customer
 * @property CustomerPlan|null $customerPlan
 * @property InvoiceItem[]  $items
 * @property Payment[]      $payments
 */
class Invoice extends ActiveRecord
{
    public const STATUS_UNPAID    = 'unpaid';
    public const STATUS_PARTIAL   = 'partial';
    public const STATUS_PAID      = 'paid';
    public const STATUS_CANCELLED = 'cancelled';

    public static function tableName(): string
    {
        return '{{%invoices}}';
    }

    public function behaviors(): array
    {
        return [
            TimestampBehavior::class,
        ];
    }

    public function rules(): array
    {
        return [
            [['invoice_number', 'customer_id', 'invoice_date', 'subtotal', 'total_amount'], 'required'],
            [['invoice_number'], 'string', 'max' => 30],
            [['invoice_number'], 'unique'],
            [['customer_id', 'customer_plan_id', 'created_by'], 'integer'],
            [['invoice_date', 'due_date'], 'date', 'format' => 'php:Y-m-d'],
            [['subtotal', 'gst_rate', 'gst_amount', 'discount_amount', 'total_amount', 'paid_amount'], 'number', 'min' => 0],
            [['status'], 'in', 'range' => [self::STATUS_UNPAID, self::STATUS_PARTIAL, self::STATUS_PAID, self::STATUS_CANCELLED]],
            [['status'], 'default', 'value' => self::STATUS_UNPAID],
            [['notes'], 'string'],
            [['customer_id'], 'exist', 'targetClass' => Customer::class, 'targetAttribute' => ['customer_id' => 'id']],
        ];
    }

    public function attributeLabels(): array
    {
        return [
            'id'               => 'ID',
            'invoice_number'   => 'Invoice #',
            'customer_id'      => 'Customer',
            'customer_plan_id' => 'Plan',
            'invoice_date'     => 'Invoice Date',
            'due_date'         => 'Due Date',
            'subtotal'         => 'Subtotal (₹)',
            'gst_rate'         => 'GST Rate (%)',
            'gst_amount'       => 'GST Amount (₹)',
            'discount_amount'  => 'Discount (₹)',
            'total_amount'     => 'Total Amount (₹)',
            'paid_amount'      => 'Paid Amount (₹)',
            'status'           => 'Status',
            'notes'            => 'Notes',
            'created_at'       => 'Created At',
        ];
    }

    public function getCustomer(): \yii\db\ActiveQuery
    {
        return $this->hasOne(Customer::class, ['id' => 'customer_id']);
    }

    public function getCustomerPlan(): \yii\db\ActiveQuery
    {
        return $this->hasOne(CustomerPlan::class, ['id' => 'customer_plan_id']);
    }

    public function getItems(): \yii\db\ActiveQuery
    {
        return $this->hasMany(InvoiceItem::class, ['invoice_id' => 'id'])->orderBy('sort_order');
    }

    public function getPayments(): \yii\db\ActiveQuery
    {
        return $this->hasMany(Payment::class, ['invoice_id' => 'id'])->orderBy(['payment_date' => SORT_ASC]);
    }

    public function getOutstandingAmount(): float
    {
        return max(0.0, (float)$this->total_amount - (float)$this->paid_amount);
    }

    public static function statusLabels(): array
    {
        return [
            self::STATUS_UNPAID    => 'Unpaid',
            self::STATUS_PARTIAL   => 'Partial',
            self::STATUS_PAID      => 'Paid',
            self::STATUS_CANCELLED => 'Cancelled',
        ];
    }
}
