<?php

namespace App\Core\Repositories;

use App\Models\Quotation;
use App\Models\QuotationSetting;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

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

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

        // Apply filters (ignore empty strings from query strings)
        if (! empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

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

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

        if (! empty($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('quotation_number', 'like', "%{$search}%")
                    ->orWhere('reference_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);
    }

    /**
     * Quotations matching filters (no pagination), for exports.
     */
    public function getFilteredCollection(array $filters = []): Collection
    {
        $query = Quotation::with(['customer', 'items']);

        if (! empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

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

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

        if (! empty($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('quotation_number', 'like', "%{$search}%")
                    ->orWhere('reference_number', 'like', "%{$search}%")
                    ->orWhereHas('customer', function ($customerQuery) use ($search) {
                        $customerQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

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

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

    /**
     * Get quotation by quotation number
     */
    public function getByQuotationNumber(string $quotationNumber): ?Quotation
    {
        return Quotation::where('quotation_number', $quotationNumber)->first();
    }

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

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

    /**
     * Update a quotation
     */
    public function update(Quotation $quotation, array $data): bool
    {
        return $quotation->update($data);
    }

    /**
     * Delete a quotation
     */
    public function delete(Quotation $quotation): bool
    {
        return $quotation->delete();
    }

    /**
     * Get expired quotations
     */
    public function getExpired(): Collection
    {
        return Quotation::where('expiry_date', '<', now())
            ->where('status', '!=', 'converted')
            ->where('status', '!=', 'cancelled')
            ->with('customer')
            ->get();
    }

    /**
     * Get quotations expiring soon
     */
    public function getExpiringSoon(int $days = 7): Collection
    {
        return Quotation::whereBetween('expiry_date', [now(), now()->addDays($days)])
            ->where('status', '!=', 'converted')
            ->where('status', '!=', 'cancelled')
            ->where('status', '!=', 'expired')
            ->with('customer')
            ->get();
    }

    /**
     * Generate next quotation number
     */
    public function generateQuotationNumber(): string
    {
        $settings = QuotationSetting::getSettings();
        $prefix = $settings->prefix ?? 'QUO';
        $numberLength = $settings->number_length ?? 6;
        $format = $settings->format ?? '{prefix}-{number}';

        $nextNumber = $settings->next_number ?? 1;

        // Format the number with leading zeros
        $formattedNumber = str_pad($nextNumber, $numberLength, '0', STR_PAD_LEFT);

        // Replace placeholders in format
        $quotationNumber = str_replace(['{prefix}', '{number}'], [$prefix, $formattedNumber], $format);

        // Check if quotation number already exists
        while (Quotation::where('quotation_number', $quotationNumber)->exists()) {
            $nextNumber++;
            $formattedNumber = str_pad($nextNumber, $numberLength, '0', STR_PAD_LEFT);
            $quotationNumber = str_replace(['{prefix}', '{number}'], [$prefix, $formattedNumber], $format);
        }

        // Update settings with next number
        $settings->next_number = $nextNumber + 1;
        $settings->save();

        return $quotationNumber;
    }
}
