<?php

namespace App\Models;

use App\Models\BaseModel;
use Illuminate\Support\Facades\DB;

class Payment extends BaseModel
{
    protected $table = 'payments';

    /**
     * CI: useTimestamps = false because DB handles created_at/updated_at (defaults/triggers).
     * Keep OFF in Laravel too.
     */
    public $timestamps = true;

    protected $fillable = [
        'parent_id',
        'invoice_id',
        'total_amount',
        'paid_amount',
        'balance',
        'number_of_installments',
        'transaction_id',
        'check_file',
        'check_number',
        'payment_method',
        'payment_date',
        'semester',
        'school_year',
        'status',
        'updated_by',
        'created_at',
        'updated_at',
    ];

    protected $casts = [
        'parent_id'               => 'integer',
        'invoice_id'              => 'integer',
        'number_of_installments'  => 'integer',
        'updated_by'              => 'integer',

        'total_amount'            => 'decimal:2',
        'paid_amount'             => 'decimal:2',
        'balance'                 => 'decimal:2',

        'payment_date'            => 'datetime',
    ];

    /* Optional relationships */
    public function invoice()
    {
        return $this->belongsTo(Invoice::class, 'invoice_id');
    }

    public function parent()
    {
        return $this->belongsTo(User::class, 'parent_id');
    }

    /* =========================
     * CI method equivalents
     * ========================= */

    public static function getPaymentsByParentId(int $parentId): array
    {
        return static::query()
            ->where('parent_id', $parentId)
            ->orderByDesc('payment_date')
            ->get()
            ->toArray();
    }

    public static function getTotalPaidByParentId(int $parentId, string $schoolYear): float
    {
        $total = DB::table('payments')
            ->where('parent_id', $parentId)
            ->where('school_year', $schoolYear)
            ->sum('paid_amount');

        return (float) $total;
    }

    public static function updateBalance(int $paymentId, float $amountPaid): bool
    {
        /** @var self|null $payment */
        $payment = static::query()->find($paymentId);
        if (!$payment) return false;

        $newBalance = (float)$payment->balance - (float)$amountPaid;

        // keep precision stable
        $paidAmount = (float)$payment->paid_amount + (float)$amountPaid;

        $affected = static::query()
            ->whereKey($paymentId)
            ->update([
                'paid_amount' => $paidAmount,
                'balance'     => $newBalance,
            ]);

        return $affected > 0;
    }

    public static function getPaymentsByYear(string $schoolYear): array
    {
        return static::query()
            ->where('school_year', $schoolYear)
            ->orderByDesc('payment_date')
            ->get()
            ->toArray();
    }

    /**
     * Generate a new transaction ID: YYYY-000001
     */
    public static function generateNewTransactionId(): string
    {
        $currentYear = date('Y');
        $prefix = $currentYear . '-';

        $latest = static::query()
            ->where('transaction_id', 'like', $prefix . '%')
            ->orderByDesc('transaction_id')
            ->first();

        if ($latest && !empty($latest->transaction_id)) {
            $lastNumber = (int) str_replace($prefix, '', (string)$latest->transaction_id);
            $newNumber = $lastNumber + 1;
        } else {
            $newNumber = 1;
        }

        return $prefix . str_pad((string)$newNumber, 6, '0', STR_PAD_LEFT);
    }

    /**
     * Get latest payment (date/amount/status) per invoice for given invoice IDs.
     * Matches your CI logic: statuses in ['Full','Paid','Partially Paid'].
     */
    public static function getPaymentsByInvoice($invoiceIds): array
    {
        if (!is_array($invoiceIds)) {
            $invoiceIds = [$invoiceIds];
        }
        $invoiceIds = array_values(array_unique(array_map('intval', array_filter($invoiceIds))));
        if (empty($invoiceIds)) return [];

        // Subquery: latest payment_date per invoice (Full/Partial only)
        $latestSub = DB::table('payments')
            ->selectRaw('invoice_id, MAX(payment_date) AS max_date')
            ->whereIn('status', ['Full', 'Paid', 'Partially Paid'])
            ->groupBy('invoice_id');

        // Main query: join payments to the latest per invoice
        $rows = DB::table('payments as p')
            ->joinSub($latestSub, 'latest', function ($join) {
                $join->on('latest.invoice_id', '=', 'p.invoice_id')
                     ->on('latest.max_date', '=', 'p.payment_date');
            })
            ->whereIn('p.invoice_id', $invoiceIds)
            ->whereIn('p.status', ['Full', 'Paid', 'Partially Paid'])
            ->select([
                'p.invoice_id',
                DB::raw('p.paid_amount AS last_paid_amount'),
                DB::raw('p.payment_date AS last_payment_date'),
                DB::raw('p.status AS last_payment_status'),
            ])
            ->get();

        return $rows->map(fn ($r) => (array) $r)->all();
    }
}