<?php

namespace App\Repositories;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

abstract class BaseRepository implements BaseRepositoryInterface
{
    /**
     * The model instance.
     */
    protected $model;

    /**
     * Create a new repository instance.
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * Get all records with optional filters.
     */
    public function getAll(array $filters = [], array $with = [])
    {
        $query = $this->model->query();

        if (!empty($with)) {
            $query->with($with);
        }

        $query = $this->applyFilters($query, $filters);

        return $query->get();
    }

    /**
     * Get paginated records.
     */
    public function getPaginated(array $filters = [], int $perPage = 15, array $with = [])
    {
        $query = $this->model->query();

        if (!empty($with)) {
            $query->with($with);
        }

        $query = $this->applyFilters($query, $filters);

        return $query->paginate($perPage);
    }

    /**
     * Find a record by ID.
     */
    public function findById($id, array $with = [])
    {
        $query = $this->model->query();

        if (!empty($with)) {
            $query->with($with);
        }

        return $query->find($id);
    }

    /**
     * Find a record by specific field.
     */
    public function findBy(string $field, $value, array $with = [])
    {
        $query = $this->model->query();

        if (!empty($with)) {
            $query->with($with);
        }

        return $query->where($field, $value)->first();
    }

    /**
     * Create a new record.
     */
    public function create(array $data)
    {
        return $this->model->create($data);
    }

    /**
     * Update a record.
     */
    public function update($id, array $data)
    {
        $record = $this->findById($id);
        if (!$record) {
            throw new \Exception("Record not found with ID: {$id}");
        }

        $record->update($data);
        return $record->fresh();
    }

    /**
     * Delete a record.
     */
    public function delete($id)
    {
        $record = $this->findById($id);
        if (!$record) {
            throw new \Exception("Record not found with ID: {$id}");
        }

        return $record->delete();
    }

    /**
     * Bulk create records.
     */
    public function bulkCreate(array $records)
    {
        return $this->model->insert($records);
    }

    /**
     * Search records.
     */
    public function search(string $query, array $fields = [], int $perPage = 15)
    {
        $queryBuilder = $this->model->query();

        if (empty($fields)) {
            // Default search fields - override in child classes
            $fields = ['name'];
        }

        $queryBuilder->where(function ($q) use ($query, $fields) {
            foreach ($fields as $field) {
                $q->orWhere($field, 'LIKE', "%{$query}%");
            }
        });

        return $queryBuilder->paginate($perPage);
    }

    /**
     * Get records count.
     */
    public function count(array $filters = [])
    {
        $query = $this->model->query();
        $query = $this->applyFilters($query, $filters);
        return $query->count();
    }

    /**
     * Check if record exists.
     */
    public function exists($id)
    {
        return $this->model->where('id', $id)->exists();
    }

    /**
     * Get model instance.
     */
    public function getModel()
    {
        return $this->model;
    }

    /**
     * Apply filters to query.
     */
    protected function applyFilters(Builder $query, array $filters)
    {
        foreach ($filters as $key => $value) {
            if ($value === null || $value === '') {
                continue;
            }

            switch ($key) {
                case 'status':
                    $query->where('status', $value);
                    break;
                case 'is_active':
                    $query->where('is_active', $value);
                    break;
                case 'created_from':
                    $query->whereDate('created_at', '>=', $value);
                    break;
                case 'created_to':
                    $query->whereDate('created_at', '<=', $value);
                    break;
                case 'search':
                    $this->applySearchFilter($query, $value);
                    break;
                default:
                    // Custom filters can be handled in child classes
                    $this->applyCustomFilter($query, $key, $value);
                    break;
            }
        }

        return $query;
    }

    /**
     * Apply search filter - override in child classes.
     */
    protected function applySearchFilter(Builder $query, $value)
    {
        // Override in child classes for specific search logic
        $query->where('name', 'LIKE', "%{$value}%");
    }

    /**
     * Apply custom filter - override in child classes.
     */
    protected function applyCustomFilter(Builder $query, string $key, $value)
    {
        // Override in child classes for specific filter logic
        if ($this->model->getConnection()->getSchemaBuilder()->hasColumn($this->model->getTable(), $key)) {
            $query->where($key, $value);
        }
    }
}