<?php

namespace App\Services\System;

use App\Enums\Permission as PermissionEnum;
use App\Enums\Role as EnumsRole;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Spatie\Permission\Models\Role;

class RoleService
{
    public function paginateForIndex(array $tableQuery): LengthAwarePaginator
    {
        $query = Role::query()
            ->withCount('permissions')
            ->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
                $search = $tableQuery['search'];
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('name', 'like', "%{$search}%");
                });
            });

        $this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']);

        return $query
            ->paginate(25)
            ->withQueryString();
    }

    public function permissionOptions(): array
    {
        return collect(PermissionEnum::cases())
            ->map(fn (PermissionEnum $permission) => [
                'value' => $permission->value,
                'label' => $permission->label(),
                'group' => $permission->group(),
            ])
            ->values()
            ->all();
    }

    public function findForEdit(Role $role): array
    {
        $role->load('permissions');

        return [
            'role' => [
                'id' => $role->id,
                'name' => $role->name,
                'permissions' => $role->permissions->pluck('name'),
            ],
        ];
    }

    public function create(array $validated): void
    {
        try {
            DB::transaction(function () use ($validated): void {
                $role = Role::create([
                    'name' => Str::slug($validated['name']),
                    'guard_name' => 'web',
                ]);

                if (! empty($validated['permissions'])) {
                    $role->syncPermissions($validated['permissions']);
                }
            });
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Throwable $e) {
            Log::error('Gagal membuat role: '.$e->getMessage(), [
                'trace' => $e->getTraceAsString(),
            ]);

            throw ValidationException::withMessages([
                'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
            ]);
        }
    }

    public function update(Role $role, array $validated): void
    {
        try {
            DB::transaction(function () use ($role, $validated): void {
                $updateData = [];
                if (! in_array($role->name, [EnumsRole::DEVELOPER->value, EnumsRole::OWNER->value], true)) {
                    $updateData['name'] = Str::slug($validated['name']);
                }
                $role->update($updateData);

                $role->syncPermissions($validated['permissions'] ?? []);
            });
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Throwable $e) {
            Log::error('Gagal memperbarui role: '.$e->getMessage(), [
                'trace' => $e->getTraceAsString(),
            ]);

            throw ValidationException::withMessages([
                'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
            ]);
        }
    }

    public function delete(Role $role): void
    {
        $role->delete();
    }

    private function applySorting(Builder $query, string $sort, string $direction): void
    {
        if (in_array($sort, ['name'], true)) {
            $query->orderBy($sort, $direction);

            return;
        }

        $query->latest();
    }
}
