<?php

namespace Modules\Roles\Services;

use App\Models\ActivityLogModel;
use App\Models\RoleModel;
use App\Models\RolePermissionModel;

class RoleService
{
    protected RoleModel $roles;
    protected RolePermissionModel $rolePermissions;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->roles           = new RoleModel();
        $this->rolePermissions = new RolePermissionModel();
        $this->activity        = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $data = [
            'name'        => $input['name'],
            'slug'        => $this->roles->generateSlug($input['name']),
            'description' => $input['description'] ?? null,
            'is_system'   => 0,
        ];

        if (! $this->roles->insert($data, true)) {
            return ['success' => false, 'errors' => $this->roles->errors()];
        }

        $id = $this->roles->getInsertID();
        $this->activity->log('roles', 'created', $actingUserId, "Created role #{$id} ({$input['name']})", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function update(int $id, array $input, ?int $actingUserId): array
    {
        $role = $this->roles->find($id);
        if (! $role) {
            return ['success' => false, 'errors' => ['id' => 'Role not found.']];
        }

        $data = ['description' => $input['description'] ?? null];

        // System roles keep their original name/slug to avoid breaking any
        // logic (like Administrator bypass patterns) that assumes it exists.
        if (! $role['is_system']) {
            $data['name'] = $input['name'];
            $data['slug'] = $this->roles->generateSlug($input['name']);
        }

        if (! $this->roles->update($id, $data)) {
            return ['success' => false, 'errors' => $this->roles->errors()];
        }

        $this->activity->log('roles', 'updated', $actingUserId, "Updated role #{$id}", (string) $id);

        return ['success' => true];
    }

    public function delete(int $id, ?int $actingUserId): array
    {
        $role = $this->roles->find($id);
        if (! $role) {
            return ['success' => false, 'error' => 'Role not found.'];
        }
        if ($role['is_system']) {
            return ['success' => false, 'error' => 'System roles cannot be deleted.'];
        }
        if ($this->roles->isInUse($id)) {
            return ['success' => false, 'error' => 'This role is assigned to one or more users and cannot be deleted.'];
        }

        $this->roles->delete($id);
        $this->activity->log('roles', 'deleted', $actingUserId, "Deleted role #{$id}", (string) $id);

        return ['success' => true];
    }

    public function syncPermissions(int $roleId, array $permissionIds, ?int $actingUserId): void
    {
        $this->rolePermissions->syncForRole($roleId, $permissionIds);
        $this->activity->log('roles', 'permissions_updated', $actingUserId, 'Updated permission matrix for role #' . $roleId, (string) $roleId);
    }
}
