<?php

namespace App\Core\Repositories;

use App\Models\Invoice;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * Invoice Repository
 * Handles all database operations for invoices
 */
class InvoiceRepository
{
    /**
     * Get all invoices
     */
    public function getAll(): Collection
    {
        return Invoice::with(['customer', 'items', 'payments'])->get();
    }

    /**
     * Get paginated invoices
     */
    public function getPaginated(int $perPage = 15, array $filters = []): LengthAwarePaginator
    {
        $query = Invoice::with(['customer', 'items', 'payments']);

        // Apply filters
        if (isset($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        if (isset($filters['customer_id'])) {
            $query->where('customer_id', $filters['customer_id']);
        }

        if (isset($filters['date_from'])) {
            $query->where('issue_date', '>=', $filters['date_from']);
        }

        if (isset($filters['date_to'])) {
            $query->where('issue_date', '<=', $filters['date_to']);
        }

        if (isset($filters['search']) && ! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('invoice_number', 'like', "%{$search}%")
                    ->orWhereHas('customer', function ($customerQuery) use ($search) {
                        $customerQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

        return $query->orderBy('created_at', 'desc')->paginate($perPage);
    }

    /**
     * Get invoice by ID
     */
    public function getById(int $id): ?Invoice
    {
        return Invoice::with(['customer', 'items', 'payments', 'reminders'])->find($id);
    }

    /**
     * Get invoice by invoice number
     */
    public function getByInvoiceNumber(string $invoiceNumber): ?Invoice
    {
        return Invoice::where('invoice_number', $invoiceNumber)->first();
    }

    /**
     * Get invoice by public token
     */
    public function getByPublicToken(string $token): ?Invoice
    {
        return Invoice::where('public_token', $token)->first();
    }

    /**
     * Create a new invoice
     */
    public function create(array $data): Invoice
    {
        return Invoice::create($data);
    }

    /**
     * Update an invoice
     */
    public function update(Invoice $invoice, array $data): bool
    {
        return $invoice->update($data);
    }

    /**
     * Delete an invoice
     */
    public function delete(Invoice $invoice): bool
    {
        return $invoice->delete();
    }

    /**
     * Get overdue invoices
     */
    public function getOverdue(): Collection
    {
        return Invoice::where('due_date', '<', now())
            ->where('status', '!=', 'paid')
            ->where('balance', '>', 0)
            ->with('customer')
            ->get();
    }

    /**
     * Get invoices due soon
     */
    public function getDueSoon(int $days = 7): Collection
    {
        return Invoice::whereBetween('due_date', [now(), now()->addDays($days)])
            ->where('status', '!=', 'paid')
            ->where('balance', '>', 0)
            ->with('customer')
            ->get();
    }

    /**
     * Generate next invoice number using InvoiceNumberingSetting
     */
    public function generateInvoiceNumber(): string
    {
        $settings = \App\Models\InvoiceNumberingSetting::getSettings();

        return $settings->generateNextNumber();
    }

    /**
     * Get preview of next invoice number (without incrementing)
     */
    public function getPreviewInvoiceNumber(): string
    {
        $settings = \App\Models\InvoiceNumberingSetting::getSettings();

        return $settings->getPreviewNumber();
    }
}
