<?php

namespace App\Livewire\Billing;

use App\Enums\InvoiceStatus;
use App\Livewire\Concerns\WithDataTable;
use App\Livewire\Concerns\WithDateRange;
use App\Models\SubscriptionInvoice;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;

/**
 * Everything billed, and what is still outstanding.
 */
#[Title('Invoices')]
class Invoices extends Component
{
    use WithDataTable, WithDateRange;

    #[Url(except: '')]
    public string $status = '';

    #[Url(except: false)]
    public bool $overdueOnly = false;

    public function mount(): void
    {
        $this->mountWithDateRange('this_year');
    }

    protected function searchableColumns(): array
    {
        return ['invoice_number', 'tenant.business_name', 'tenant.owner_name'];
    }

    protected function defaultSort(): array
    {
        return ['issued_on', 'desc'];
    }

    protected function sortableColumns(): array
    {
        return ['issued_on', 'due_on', 'total', 'paid_amount', 'invoice_number'];
    }

    protected function filterProperties(): array
    {
        return ['status', 'overdueOnly'];
    }

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

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

    protected function baseQuery(): Builder
    {
        return SubscriptionInvoice::query()->with(['tenant', 'subscription.plan']);
    }

    protected function applyFilters(Builder $query): Builder
    {
        if ($this->status !== '') {
            $query->where('status', $this->status);
        }

        if ($this->overdueOnly) {
            $query->whereNotIn('status', [InvoiceStatus::Paid->value, InvoiceStatus::Cancelled->value])
                ->whereNotNull('due_on')
                ->whereDate('due_on', '<', now());
        }

        if ($from = $this->fromDate()) {
            $query->whereDate('issued_on', '>=', $from);
        }

        if ($to = $this->toDate()) {
            $query->whereDate('issued_on', '<=', $to);
        }

        return $query;
    }

    public function rows()
    {
        return $this->applyDataTable($this->applyFilters($this->baseQuery()))
            ->paginate($this->perPage);
    }

    /** Totals for the filtered set, not just the visible page. */
    public function totals(): array
    {
        $query = $this->applyFilters($this->baseQuery());

        return [
            'billed' => (float) (clone $query)->sum('total'),
            'collected' => (float) (clone $query)->sum('paid_amount'),
            'count' => (clone $query)->count(),
        ];
    }

    public function render()
    {
        $totals = $this->totals();

        return view('livewire.billing.invoices', [
            'rows' => $this->rows(),
            'statuses' => InvoiceStatus::options(),
            'totals' => $totals,
            'outstanding' => round($totals['billed'] - $totals['collected'], 2),
        ]);
    }
}
