<?php

namespace App\Models\Control;

use CodeIgniter\Model;
use Config\Lookups;

/**
 * Control DB. Platform billing a hotel for their PMS subscription — see
 * CreateInvoicesTable. Mirrors the shape of a tenant's own folio
 * invoicing (generate → send → collect payment → mark paid) but this is
 * platform revenue, not hotel operational data.
 */
class InvoiceModel extends Model
{
    protected $table            = 'invoices';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'tenant_id',
        'subscription_id',
        'invoice_number',
        'amount',
        'status',
        'due_date',
        'paid_at',
    ];

    public function __construct()
    {
        parent::__construct();

        $statuses = array_keys((new Lookups())->invoiceStatuses);

        $this->validationRules = [
            'tenant_id'      => 'required|integer',
            'invoice_number' => 'required|max_length[30]|is_unique[invoices.invoice_number,id,{id}]',
            'amount'         => 'required|decimal',
            'status'         => 'required|in_list[' . implode(',', $statuses) . ']',
        ];
    }

    /**
     * INV-{year}-{6-digit sequence within that year}. Sequence is a plain
     * COUNT+1 (Phase 1's UserModel/BookingModel establish that a small
     * platform doesn't need gap-free sequence generators) — good enough
     * at this scale, never user-entered either way.
     */
    public function nextInvoiceNumber(): string
    {
        $year  = date('Y');
        $count = $this->like('invoice_number', "INV-{$year}-", 'after')->countAllResults();

        return sprintf('INV-%s-%06d', $year, $count + 1);
    }

    public function forTenant(int $tenantId): array
    {
        return $this->where('tenant_id', $tenantId)->orderBy('created_at', 'desc')->findAll();
    }

    public function markPaid(int $id): void
    {
        $this->update($id, ['status' => 'paid', 'paid_at' => date('Y-m-d H:i:s')]);
    }

    public function totalCollected(): string
    {
        $sum = $this->where('status', 'paid')->selectSum('amount')->first();

        return $sum->amount ?? '0.00';
    }

    public function totalOutstanding(): string
    {
        $sum = $this->whereIn('status', ['sent', 'overdue'])->selectSum('amount')->first();

        return $sum->amount ?? '0.00';
    }

    public function countByStatus(string $status): int
    {
        return $this->where('status', $status)->countAllResults();
    }

    /**
     * Joined with tenants so the invoice list can show hotel name without
     * an N+1 per row.
     */
    public function allWithTenant(): array
    {
        return $this->select('invoices.*, tenants.hotel_name, tenants.slug as tenant_slug')
            ->join('tenants', 'tenants.id = invoices.tenant_id')
            ->orderBy('invoices.created_at', 'desc')
            ->findAll();
    }
}
