<?php

namespace Modules\Role\Repositories;

use App\Models\Permission;
use Illuminate\Support\Facades\DB;
use Modules\Role\Entities\Role;
use Modules\Role\Repositories\Contracts\RoleRepositoryInterface;

class RoleRepository implements RoleRepositoryInterface
{
    protected $model;

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

    /**
     * Get all roles
     */
    public function all()
    {
        return $this->model->where('name', '!=', 'DEVELOPER')->get();
    }

    /**
     * Find role by ID
     */
    public function find($id)
    {
        return $this->model->findOrFail($id);
    }

    /**
     * Find role by ID (alias for find)
     */
    public function findById($id)
    {
        return $this->find($id);
    }

    /**
     * Create a new role
     */
    public function create(array $data)
    {
        return DB::transaction(function () use ($data) {
            $role = $this->model->create([
                'name' => $data['name'],
                'guard_name' => $data['guard_name'] ?? 'api',
                'fullname' => $data['fullname'] ?? null,
                'context' => $data['context'] ?? 'member',
            ]);

            if (isset($data['permissions']) && is_array($data['permissions'])) {
                $this->syncPermissions($role, $data['permissions']);
            }

            return $role->load('permissions');
        });
    }

    /**
     * Update role
     */
    public function update($id, array $data)
    {
        return DB::transaction(function () use ($id, $data) {
            $role = $this->find($id);

            $role->update([
                'name' => $data['name'],
                'guard_name' => $data['guard_name'] ?? $role->guard_name,
                'fullname' => $data['fullname'] ?? $role->fullname,
                'context' => $data['context'] ?? $role->context ?? 'member',
            ]);

            if (isset($data['permissions']) && is_array($data['permissions'])) {
                $this->syncPermissions($role, $data['permissions']);
            }

            return $role->load('permissions');
        });
    }

    /**
     * Delete role
     */
    public function delete($id)
    {
        $role = $this->find($id);
        return $role->delete();
    }

    /**
     * Get roles with permissions
     */
    public function withPermissions($search = '')
    {
        $query = $this->model->with('permissions')
            ->where('name', '!=', 'DEVELOPER');
        
        if (!empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('name', 'ILIKE', "%{$search}%")
                  ->orWhere('fullname', 'ILIKE', "%{$search}%")
                  ->orWhere('guard_name', 'ILIKE', "%{$search}%");
            });
        }
        
        return $query->get();
    }

    /**
     * Sync permissions for a role
     */
    public function syncPermissions(Role $role, array $permissionIds)
    {
        $permissionIds = array_map(fn ($id) => (string) $id, $permissionIds);

        $permissions = Permission::whereIn('id', $permissionIds)->get();

        if ($permissions->count() !== count($permissionIds)) {
            throw new \InvalidArgumentException('One or more selected permissions do not exist.');
        }

        $role->syncPermissions($permissions);

        return $role;
    }
}
