<?php

namespace App\Models;

use CodeIgniter\Model;

class PaymentModel extends Model
{
    protected $table = 'payments';
    protected $primaryKey = 'id';
    protected $returnType = 'array';

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

    protected $useTimestamps = false;
    // ❗ Your DB handles created_at / updated_at with default CURRENT_TIMESTAMP
    // Remove CI4 auto timestamp management unless you modify your DB schema

    protected $validationRules = [
        'parent_id' => 'required|integer',
        'invoice_id' => 'required|integer',
        'total_amount' => 'required|decimal',
        'paid_amount' => 'required|decimal',
        'balance' => 'required|decimal',
        'number_of_installments' => 'required|integer',
        'payment_method' => 'required|max_length[50]', // ✅ Removed 'string'
        'payment_date' => 'required|valid_date[Y-m-d H:i:s]',
        'status' => 'required|max_length[50]', // ✅ Removed 'string'
        'check_number' => 'permit_empty|max_length[100]',
    ];

    protected $validationMessages = [
        'parent_id' => [
            'required' => 'Parent ID is required.',
            'integer' => 'Parent ID must be an integer.',
        ],
        'invoice_id' => [
            'required' => 'Invoice ID is required.',
            'integer' => 'Invoice ID must be an integer.',
        ],
        'total_amount' => [
            'required' => 'Total amount is required.',
            'decimal' => 'Total amount must be a valid decimal.',
        ],
        'paid_amount' => [
            'required' => 'Paid amount is required.',
            'decimal' => 'Paid amount must be a valid decimal.',
        ],
        'balance' => [
            'required' => 'Balance is required.',
            'decimal' => 'Balance must be a valid decimal.',
        ],
        'payment_date' => [
            'required' => 'Payment date is required.',
            'valid_date' => 'Payment date must be a valid date (Y-m-d H:i:s).',
        ],
        'payment_method' => [
            'required' => 'Payment method is required.',
            'max_length' => 'Payment method must not exceed 50 characters.',
        ],
        'status' => [
            'required' => 'Status is required.',
            'max_length' => 'Status must not exceed 50 characters.',
        ],
        'number_of_installments' => [
            'required' => 'Number of installments is required.',
            'integer' => 'Number of installments must be an integer.',
        ],
        'check_number' => [
            'max_length' => 'Check number must not exceed 100 characters.',
        ]
    ];

    /**
     * Get payments by parent ID.
     *
     * @param int $parentId
     * @return array
     */
    public function getPaymentsByParentId(int $parentId): array
    {
        return $this->where('parent_id', $parentId)
            ->orderBy('payment_date', 'DESC')
            ->findAll();
    }

    /**
     * Calculate the total paid amount for a specific parent.
     *
     * @param int $parentId
     * @return float
     */
    public function getTotalPaidByParentId(int $parentId, string $schoolYear): float
    {
        $db = \Config\Database::connect();

        $result = $db->table('payments')
            ->selectSum('paid_amount', 'total_paid')
            ->where('parent_id', $parentId)
            ->where('school_year', $schoolYear)
            ->get()
            ->getRowArray();

        return $result && isset($result['total_paid']) ? (float) $result['total_paid'] : 0.00;
    }


    /**
     * Update balance for a specific payment.
     *
     * @param int $paymentId
     * @param float $amountPaid
     * @return bool
     */
    public function updateBalance(int $paymentId, float $amountPaid): bool
    {
        $payment = $this->find($paymentId);
        if (!$payment) {
            return false;
        }

        $newBalance = $payment['balance'] - $amountPaid;

        return $this->update($paymentId, [
            'paid_amount' => $payment['paid_amount'] + $amountPaid,
            'balance' => $newBalance
        ]);
    }

    /**
     * Get payments by school year.
     *
     * @param string $schoolYear
     * @return array
     */
    public function getPaymentsByYear(string $schoolYear): array
    {
        return $this->where('school_year', $schoolYear)
            ->orderBy('payment_date', 'DESC')
            ->findAll();
    }

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

        $latest = $this->like('transaction_id', $prefix, 'after')
            ->orderBy('transaction_id', 'DESC')
            ->first();

        if ($latest && isset($latest['transaction_id'])) {
            $lastNumber = (int) str_replace($prefix, '', $latest['transaction_id']);
            $newNumber = $lastNumber + 1;
        } else {
            $newNumber = 1;
        }

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

    public function getPaymentsByInvoice($invoiceIds): array
    {
        // Normalize input
        if (!is_array($invoiceIds)) {
            $invoiceIds = [$invoiceIds];
        }
        if (empty($invoiceIds)) {
            return [];
        }

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

        // Main query: join payments to the latest per invoice
        $rows = $this->db->table('payments p')
            ->select('p.invoice_id, p.paid_amount AS last_paid_amount, p.payment_date AS last_payment_date, p.status AS last_payment_status')
            ->join("($latestSub) latest", 'latest.invoice_id = p.invoice_id AND latest.max_date = p.payment_date', 'inner', false) // <-- escape=false
            ->whereIn('p.invoice_id', $invoiceIds)
            ->whereIn('p.status', ['Full', 'Paid', 'Partially Paid'])
            ->get()
            ->getResultArray();

        return $rows;
    }
}
