<?php

namespace App\Core\Repositories;

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

/**
 * Journal Entry Repository
 * Handles all database operations for journal entries
 */
class JournalEntryRepository
{
    /**
     * Get all journal entries
     */
    public function getAll(): Collection
    {
        return JournalEntry::with(['lines.account', 'creator'])->get();
    }

    /**
     * Get paginated journal entries
     */
    public function getPaginated(int $perPage = 15, array $filters = []): LengthAwarePaginator
    {
        $query = JournalEntry::with(['lines.account', 'creator']);

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

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

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

        if (isset($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('entry_number', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%");
            });
        }

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

    /**
     * Get journal entry by ID
     */
    public function getById(int $id): ?JournalEntry
    {
        return JournalEntry::with(['lines.account', 'creator', 'reverser'])->find($id);
    }

    /**
     * Get journal entry by entry number
     */
    public function getByEntryNumber(string $entryNumber): ?JournalEntry
    {
        return JournalEntry::where('entry_number', $entryNumber)->first();
    }

    /**
     * Create a new journal entry
     */
    public function create(array $data): JournalEntry
    {
        return JournalEntry::create($data);
    }

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

    /**
     * Delete a journal entry
     */
    public function delete(JournalEntry $entry): bool
    {
        if ($entry->status === 'posted') {
            throw new \Exception('Posted journal entries cannot be deleted.');
        }

        return $entry->delete();
    }

    /**
     * Generate next entry number
     */
    public function generateEntryNumber(): string
    {
        $prefix = config('accounting.journal_prefix', 'JE');
        $year = now()->year;
        $lastEntry = JournalEntry::whereYear('created_at', $year)
            ->orderBy('id', 'desc')
            ->first();

        if ($lastEntry) {
            $lastNumber = (int) substr($lastEntry->entry_number, -6);
            $nextNumber = $lastNumber + 1;
        } else {
            $nextNumber = 1;
        }

        return $prefix.'-'.$year.'-'.str_pad($nextNumber, 6, '0', STR_PAD_LEFT);
    }
}
