<?php

namespace App\Livewire\Admin;

use App\Models\Invoice;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

/**
 * Every document that has been issued, newest first.
 *
 * Read-only by design, and that is the feature. An issued invoice cannot be
 * edited or deleted here or anywhere else — a wrong one is corrected by issuing
 * a cancellation and a new document, which is the only lawful way to correct
 * one. There is no edit button to explain the absence of.
 */
#[Layout('layouts.admin')]
class Invoices extends Component
{
    use WithPagination;

    #[Url]
    public string $search = '';

    #[Url]
    public string $year = '';

    public function mount(): void
    {
        $this->authorize('site.manage');
    }

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function updatedYear(): void
    {
        $this->resetPage();
    }

    public function render()
    {
        $invoices = Invoice::query()
            ->with(['customer', 'series'])
            ->when($this->search !== '', function ($q) {
                $term = '%'.$this->search.'%';
                $q->where(fn ($w) => $w->where('number', 'like', $term)
                    ->orWhereHas('customer', fn ($c) => $c->where('name', 'like', $term)));
            })
            ->when($this->year !== '', fn ($q) => $q->whereYear('issued_on', (int) $this->year))
            ->orderByDesc('issued_on')
            ->orderByDesc('id')
            ->paginate(25);

        return view('livewire.admin.invoices', [
            'invoices' => $invoices,
            // Straight from the rows rather than a fixed range: a list of years
            // with nothing in them is a filter that mostly returns nothing.
            //
            // Derived in PHP rather than with YEAR() in raw SQL. That function
            // is MySQL's; SQLite has no such thing, and a query that only runs
            // on one engine turns the test database into a different product
            // from the real one.
            'years' => Invoice::query()
                ->orderByDesc('issued_on')
                ->pluck('issued_on')
                // ->local() even for a year (R19): on New Year's night the UTC
                // year is still the previous one, so the filter would offer a
                // year the operator is no longer in.
                ->map(fn ($date) => $date?->local()->format('Y'))
                ->filter()
                ->unique()
                ->values(),
        ]);
    }
}
