<?php

namespace Modules\User\Repositories;

use Illuminate\Database\Eloquent\Collection;
use Modules\Auth\Entities\User;
use Modules\User\Repositories\Contracts\UserRepositoryInterface;

class UserRepository implements UserRepositoryInterface
{
    private function applySearch($query, string $search): void
    {
        if (empty($search)) {
            return;
        }

        $query->where(function ($q) use ($search) {
            $q->where('name', 'ILIKE', "%{$search}%")
                ->orWhere('ic_number', 'ILIKE', "%{$search}%")
                ->orWhere('email', 'ILIKE', "%{$search}%")
                ->orWhere('phone_number', 'ILIKE', "%{$search}%")
                ->orWhere('member_number', 'ILIKE', "%{$search}%")
                ->orWhereHas('roles', function ($roleQuery) use ($search) {
                    $roleQuery->whereRaw('LOWER(name) ILIKE ?', ['%' . strtolower($search) . '%']);
                });
        });
    }

    /**
     * Get all Users with pagination and search
     */
    public function getAllPaginated(int $perPage = 10, string $search = '')
    {
        $query = User::excludeDevelopersUnlessDeveloper()->orderBy('name');

        $this->applySearch($query, $search);

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

    /**
     * Get all Users with their relationships and pagination with search
     */
    public function getAllWithRelationsPaginated(
        int $perPage = 10,
        string $search = '',
        string $status = '',
        string $sortBy = 'name',
        string $sortOrder = 'asc'
    ) {
        $allowedSortColumns = [
            'id',
            'name',
            'email',
            'position',
            'status',
            'member_number',
            'created_at',
            'deleted_at',
        ];
        $sortBy = in_array($sortBy, $allowedSortColumns, true) ? $sortBy : 'name';
        $sortOrder = strtolower($sortOrder) === 'desc' ? 'desc' : 'asc';

        $query = User::excludeDevelopersUnlessDeveloper()
            ->with([
                'roles:id,name,guard_name'
            ])
            ->orderBy($sortBy, $sortOrder);

        $this->applySearch($query, $search);

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

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

    /**
     * Get soft-deleted Users with their relationships and pagination
     */
    public function getDeletedWithRelationsPaginated(
        int $perPage = 10,
        string $search = '',
        string $status = '',
        string $sortBy = 'deleted_at',
        string $sortOrder = 'desc'
    ) {
        $allowedSortColumns = [
            'id',
            'name',
            'email',
            'position',
            'status',
            'member_number',
            'created_at',
            'deleted_at',
        ];
        $sortBy = in_array($sortBy, $allowedSortColumns, true) ? $sortBy : 'deleted_at';
        $sortOrder = strtolower($sortOrder) === 'desc' ? 'desc' : 'asc';

        $query = User::onlyTrashed()
            ->excludeDevelopersUnlessDeveloper()
            ->with([
                'roles:id,name,guard_name',
            ])
            ->orderBy($sortBy, $sortOrder);

        $this->applySearch($query, $search);

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

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

    /**
     * Get all Users with their relationships and search
     */
    public function getAllWithRelations(string $search = ''): Collection
    {
        $query = User::excludeDevelopersUnlessDeveloper()->orderBy('name');

        $this->applySearch($query, $search);

        return $query->get();
    }

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

    /**
     * Find User by ID
     */
    public function findById(string $id): ?User
    {
        return User::with(['roles'])->find($id);
    }

    /**
     * Delete User (soft delete)
     */
    public function delete(string $id): bool
    {
        $User = User::find($id);
        if ($User) {
            return $User->delete();
        }

        return false;
    }

    /**
     * Find soft-deleted User by ID
     */
    public function findTrashedById(string $id): ?User
    {
        return User::onlyTrashed()->with(['roles'])->find($id);
    }

    /**
     * Restore a soft-deleted User
     */
    public function restore(string $id): bool
    {
        $user = User::onlyTrashed()->find($id);

        if ($user) {
            return (bool) $user->restore();
        }

        return false;
    }

    /**
     * Get all Ranks
     */
    public function all(string $search = ''): Collection
    {
        $query = User::excludeDevelopersUnlessDeveloper()->orderBy('name');

        $this->applySearch($query, $search);

        return $query->get();
    }
}
