<?php

namespace Modules\Inventory\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Accounts\Models\Traits\HasAccountingPeriod;
use Modules\Accounts\Models\Traits\HasFiscalYear;
use Modules\Accounts\Models\Traits\HasSourceVatTransactions;
use Modules\Approval\Contracts\ApprovableDocumentInterface;
use Modules\Approval\Contracts\ApprovalSearchableInterface;
use Modules\Approval\Models\ApprovalWorkflow;
use Modules\Approval\Traits\Approvable;
use Modules\Billing\Enums\BillPayStatusEnum;
use Modules\Core\Traits\AuditableTrait;
use Modules\Core\Traits\HasApprover;
use Modules\Core\Traits\HasCanceller;
use Modules\Inventory\Enums\PurchaseStatusEnum;
use Modules\Inventory\Models\Traits\HasPurchasePayments;
use Modules\Inventory\Models\Traits\HasPurchaseRequisition;
use Modules\Inventory\Models\Traits\HasSupplier;
use Modules\Inventory\Models\Traits\PurchaseInvRelationshipTrait;
use Modules\Inventory\Services\ApprovalHandlers\PurchaseInvoiceApprovalHandler;

class PurchaseInvoice extends Model implements ApprovableDocumentInterface, ApprovalSearchableInterface
{
    use Approvable,
        HasSupplier,
        HasFiscalYear,
        HasAccountingPeriod,
        HasPurchaseRequisition,
        HasSourceVatTransactions,
        HasPurchasePayments,
        PurchaseInvRelationshipTrait,
        AuditableTrait,
        HasApprover,
        HasCanceller,
        SoftDeletes;

    protected $fillable = [
        'fiscal_year_id',
        'accounting_period_id',
        'purchase_requisition_id',
        'invoice_no',
        'supplier_id',
        'voucher_id',
        'invoice_date',
        'subtotal',
        'total_discount',
        'taxable_amount',
        'total_vat',
        'rounding_adjustment',
        'grand_total',
        'paid_amount',
        'due_amount',
        'payment_status',
        'is_posted',
        'status',
        'note',
        'submitted_at',
        'approved_at',
        'rejected_at',
        'posted_at',
        'posted_by',
        'created_by',
        'updated_by'
    ];

    protected $casts = [
        'invoice_date' => 'date',
        'submitted_at' => 'datetime',
        'approved_at' => 'datetime',
        'rejected_at' => 'datetime',
        'posted_at' => 'datetime',
        'is_posted' => 'boolean'
    ];

    public static function approvalWorkflowCode(): string
    {
        return ApprovalWorkflow::PURCHASE_INVOICE;
    }

    public function approvalDocumentNumber(): string
    {
        return $this->invoice_no;
    }

    public function approvalDocumentDate(): ?string
    {
        return $this->invoice_date;
    }

    public function approvalDocumentAmount(): ?string
    {
        return $this->grand_total;
    }

    public function approvalApiEndpoint(): string
    {
        return route('api.inventory-management.purchase.show', $this->id);
    }

    public function approvalFrontendRoute(): string
    {
        $path = trim(config('core.frontend_paths.purchase_show'), '/');

        return "/{$path}/{$this->id}";
    }

    public function approvalHandler(): string
    {
        return PurchaseInvoiceApprovalHandler::class;
    }

    public function isEligibleForPosting(): bool
    {
        return $this->status === PurchaseStatusEnum::APPROVED->value && !$this->is_posted;
    }

    public function scopeSearch(Builder $query, ?string $search): Builder
    {
        if (blank($search)) {
            return $query;
        }

        return $query->where(function ($q) use ($search) {
            $like = "%{$search}%";

            $q->where('invoice_no', 'like', $like)
                ->orWhereHas('supplier', function ($supplier) use ($like) {
                    $supplier->where('name', 'like', $like);
                });
        });
    }

    public function scopeFilterStatus(Builder $query, ?PurchaseStatusEnum $status): Builder
    {
        return $query->when($status,
            fn ($q) => $q->where('status', $status->value)
        );
    }

    public function scopePaymentStatus(Builder $query, ?BillPayStatusEnum $pStatus): Builder
    {
        return $query->when($pStatus,
            fn ($q) => $q->where('payment_status', $pStatus->value)
        );
    }

    public function scopeInvoiceDateBetween(Builder $query, ?string $from, ?string $to): Builder
    {
        return $query->when($from,
            fn ($q) => $q->whereDate('invoice_date', '>=', $from)
        )->when($to,
            fn ($q) => $q->whereDate('invoice_date', '<=', $to)
        );
    }

    public function scopeDraft(Builder $query): Builder
    {
        return $query->where('status', PurchaseStatusEnum::DRAFT->value);
    }

    public function scopeApproved(Builder $query): Builder
    {
        return $query->where('status', PurchaseStatusEnum::APPROVED->value);
    }

    public function scopePosted(Builder $query): Builder
    {
        return $query->where('is_posted', true);
    }

    public function scopeUnpaid(Builder $query): Builder
    {
        return $query->where('payment_status', BillPayStatusEnum::UNPAID->value);
    }

    public function scopeHasDue(Builder $query): Builder
    {
        return $query->where('due_amount', '>', 0);
    }

    public function scopeApprovalSearch(Builder $query, string $search): Builder
    {
        return $query->where(function (Builder $subQuery) use ($search) {
            $like = "%{$search}%";

            $subQuery->where('invoice_no', 'like', $like);
                //->orWhere('status', 'like', "%{$like}%");
        });
    }
}

