<?php

namespace App\Services\Agent;

use App\Models\AdminRole;
use App\Models\AdminUser;
use App\Models\AgentNode;
use App\Support\AdminPermissionInheritance;
use App\Support\AgentRoleAuthorization;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

final class AgentRoleService
{
    /**
     * @param  array{slug: string, name: string, description?: ?string, status?: int, permission_slugs?: list<string>}  $payload
     */
    public function createForAgent(AdminUser $actor, AgentNode $owner, array $payload): AdminRole
    {
        $permissionSlugs = AdminPermissionInheritance::expand(
            array_values(array_unique($payload['permission_slugs'] ?? [])),
        );

        AgentRoleAuthorization::assertSlugsForAgentRole(
            $actor,
            $owner,
            $permissionSlugs,
        );

        $slug = trim((string) $payload['slug']);
        if (AdminRole::query()
            ->where('owner_agent_id', $owner->id)
            ->where('slug', $slug)
            ->exists()) {
            throw ValidationException::withMessages(['slug' => ['unique']]);
        }

        return DB::transaction(function () use ($payload, $owner, $slug, $permissionSlugs): AdminRole {
            $role = AdminRole::query()->create([
                'slug' => $slug,
                'code' => $slug,
                'name' => trim((string) $payload['name']),
                'description' => $payload['description'] ?? null,
                'status' => (int) ($payload['status'] ?? 1) === 0 ? 0 : 1,
                'is_system' => false,
                'sort_order' => 0,
                'scope_type' => AdminRole::SCOPE_AGENT,
                'owner_agent_id' => $owner->id,
                'delegated_from_role_id' => null,
            ]);

            $role->syncLegacyPermissionSlugs($permissionSlugs);

            return $role->fresh();
        });
    }

    /**
     * @param  array{name?: string, description?: ?string, status?: int}  $payload
     */
    public function update(AdminRole $role, array $payload): AdminRole
    {
        if (array_key_exists('name', $payload)) {
            $name = trim((string) $payload['name']);
            if ($name !== '') {
                $role->name = $name;
            }
        }

        if (array_key_exists('description', $payload)) {
            $role->description = $payload['description'];
        }

        if (array_key_exists('status', $payload)) {
            $role->status = (int) $payload['status'] === 0 ? 0 : 1;
        }

        $role->save();

        return $role->fresh();
    }

    /**
     * @param  list<string>  $permissionSlugs
     */
    public function syncPermissions(AdminUser $actor, AdminRole $role, array $permissionSlugs): AdminRole
    {
        $permissionSlugs = AdminPermissionInheritance::expand($permissionSlugs);
        $owner = AgentNode::query()->findOrFail((int) $role->owner_agent_id);
        AgentRoleAuthorization::assertSlugsForAgentRole($actor, $owner, $permissionSlugs);
        $role->syncLegacyPermissionSlugs($permissionSlugs);

        return $role->fresh();
    }

    public function destroy(AdminRole $role): void
    {
        if ($role->is_system) {
            throw ValidationException::withMessages(['role' => ['system_role']]);
        }

        if ($role->assignedUserCount() > 0) {
            throw ValidationException::withMessages([
                'role' => [
                    __('admin.agent_role_in_use', ['count' => $role->assignedUserCount()]),
                ],
            ]);
        }

        $role->delete();
    }
}
