<?php

namespace Modules\Inventory\Repositories;

use Illuminate\Database\Eloquent\Collection;
use Modules\Accounts\Models\ChartOfAccount;
use Modules\Core\Enums\PaymentStatusEnum;
use Modules\Core\Enums\StatusEnum;
use Modules\Inventory\DTO\PurchasePaymentAccountFilter;
use Modules\Inventory\Models\PurchaseInvoice;
use Modules\Inventory\Models\PurchasePayment;

class PurchasePaymentRepository
{
    public function searchPaymentAccounts(PurchasePaymentAccountFilter $filters): Collection
    {
        return ChartOfAccount::query()
            ->active()
            ->ledger()
            ->cashOrBank()
            ->search($filters->search)
            ->orderBy('account_code')
            ->limit($filters->perPage ?? 20)
            ->get(['id', 'account_name', 'account_code']);
    }

    public function paginate(int $perPage = 20)
    {
        return PurchasePayment::query()
            ->with([
                'purchaseInvoice:id,invoice_no,grand_total,paid_amount,due_amount,payment_status',
                'account:id,account_code,account_name',
            ])
            ->latest()
            ->paginate($perPage);
    }

    public function getByInvoice(PurchaseInvoice $purchase)
    {
        return $purchase->payments()
            ->with([
                'account:id,account_code,account_name',
                'voucher:id,voucher_no',
            ])
            ->latest('id')
            ->get();
    }

    public function create(array $data): PurchasePayment
    {
        return PurchasePayment::create($data);
    }

    public function findById(int $id, array $columns = ['*'], array $relations = []): PurchasePayment
    {
        return PurchasePayment::query()
            ->with($relations)
            ->select($columns)
            ->findOrFail($id);
    }

    public function find(int $id)
    {
        return PurchasePayment::findOrFail($id);
    }

    public function findForUpdate(int $id, array $columns = ['*'], array $relations = []): PurchasePayment
    {
        return PurchasePayment::query()
            ->with($relations)
            ->select($columns)
            ->lockForUpdate()
            ->findOrFail($id);
    }

    public function update(PurchasePayment $payment, array $data): PurchasePayment
    {
        $payment->update($data);

        return $payment->fresh();
    }

    public function getReservedAmountByInvoice(int $invoiceId, ?int $excludePaymentId = null): string
    {
        return (string) PurchasePayment::query()
            ->where('purchase_invoice_id', $invoiceId)
            ->whereIn('status', [
                PaymentStatusEnum::DRAFT->value,
                PaymentStatusEnum::SUBMITTED->value,
                PaymentStatusEnum::APPROVED->value,
            ])
            ->when($excludePaymentId, fn ($query) => $query->where('id', '!=', $excludePaymentId))
            ->sum('amount');
    }

    public function delete(PurchasePayment $payment): void
    {
        $payment->delete();
    }
}
