<?php

namespace App\Repositories;

use App\Repositories\Contracts\CrudRepositoryInterface;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

class BaseRepository implements CrudRepositoryInterface
{
    protected $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    public function getAll(array $filters = []): Collection
    {
        return $this->applyFilters($this->model->newQuery(), $filters)->latest()->get();
    }

    public function paginate(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $perPage = max(1, min($perPage, 500));

        return $this->applyFilters($this->model->newQuery(), $filters)
            ->latest()
            ->paginate($perPage)
            ->onEachSide(5);
    }

    public function getById(string $id): Model
    {
        return $this->model->newQuery()->findOrFail($id);
    }

    public function save(array $data): Model
    {
        $record = $this->model->newInstance();
        $record->forceFill($data);
        $record->saveOrFail();

        return $record->refresh();
    }

    public function update(string $id, array $data): Model
    {
        $record = $this->getById($id);
        $record->forceFill($data);
        $record->saveOrFail();

        return $record->refresh();
    }

    public function delete(string $id): bool
    {
        return (bool) $this->getById($id)->delete();
    }

    public function all()
    {
        return $this->getAll();
    }

    public function find($id)
    {
        return $this->getById((string) $id);
    }

    public function create(array $data)
    {
        return $this->save($data);
    }

    public function findDuplicate($column, $value, $excludeId = null): bool
    {
        $query = $this->model->newQuery()->where($column, $value);

        if ($excludeId) {
            $query->where($this->model->getKeyName(), '!=', $excludeId);
        }

        return $query->exists();
    }

    protected function applyFilters($query, array $filters)
    {
        foreach ($filters as $column => $value) {
            if ($value === null || $value === '') {
                continue;
            }

            if (is_array($value)) {
                $query->whereIn($column, $value);
                continue;
            }

            $query->where($column, $value);
        }

        return $query;
    }
}
