<?php

namespace App\Modules\Settings\Rbac\Services;

use App\Models\User;
use App\Modules\Admin\Tenancy\Models\Tenant;
use App\Modules\Navigation\Services\NavigationService;
use App\Modules\Settings\Rbac\DTOs\TenantUserWriteData;
use App\Modules\Settings\Rbac\Repositories\TenantUserRepository;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class TenantUserManagementService
{
    public function __construct(
        private readonly TenantUserRepository $users,
        private readonly TenantUserRoleService $roles,
        private readonly TenantUserEmployeeLinkService $employeeLinks,
        private readonly RbacAuditService $audit,
    ) {}

    public function update(Tenant $tenant, User $user, TenantUserWriteData $data): User
    {
        $this->assertTenant($tenant, $user);
        if ($this->users->emailTaken($data->email, (int) $user->id)) {
            throw ValidationException::withMessages([
                'email' => [__('rbac.validation.email_taken')],
            ]);
        }

        $updated = DB::transaction(function () use ($tenant, $user, $data): User {
            $updated = $this->users->update($user, [
                'name' => $data->name,
                'email' => $data->email,
            ]);
            if (! $user->isTenantOwner()) {
                $this->roles->syncRoles($tenant, $updated, $data->roleIds);
            }
            $this->employeeLinks->sync($tenant, $updated, $data->employeeId);

            return $this->users->find((int) $tenant->id, (int) $updated->id) ?? $updated;
        });
        $this->forget($updated);
        $this->audit->user($updated, 'updated');

        return $updated;
    }

    public function resetPassword(Tenant $tenant, User $user, User $actor, string $password): void
    {
        $this->assertTenant($tenant, $user);
        if ($user->is($actor) || $user->isTenantOwner()) {
            throw ValidationException::withMessages([
                'password' => [__('rbac.validation.password_reset_protected')],
            ]);
        }
        $this->users->update($user, [
            'password' => Hash::make($password),
            'remember_token' => Str::random(60),
        ]);
        $this->users->clearSessions($user);
        $this->users->clearPasswordResetTokens($user);
        $this->audit->user($user, 'password_reset');
    }

    public function deactivate(Tenant $tenant, User $user, User $actor): void
    {
        $this->assertLifecycleAllowed($tenant, $user, $actor);
        $updated = $this->users->update($user, [
            'is_active' => false,
            'deactivated_at' => now(),
            'remember_token' => Str::random(60),
            'invitation_token' => null,
            'invitation_expires_at' => null,
        ]);
        $this->users->clearSessions($updated);
        $this->users->clearPasswordResetTokens($updated);
        $this->forget($updated);
        $this->audit->user($updated, 'deactivated');
    }

    public function activate(Tenant $tenant, User $user): void
    {
        $this->assertTenant($tenant, $user);
        $updated = $this->users->update($user, [
            'is_active' => true,
            'deactivated_at' => null,
        ]);
        $this->forget($updated);
        $this->audit->user($updated, 'activated');
    }

    private function assertLifecycleAllowed(Tenant $tenant, User $user, User $actor): void
    {
        $this->assertTenant($tenant, $user);
        if ($user->is($actor) || $user->isTenantOwner()) {
            throw ValidationException::withMessages([
                'user' => [__('rbac.validation.user_deactivate_protected')],
            ]);
        }
    }

    private function assertTenant(Tenant $tenant, User $user): void
    {
        abort_if((int) $tenant->id !== (int) $user->tenant_id || $user->isAdmin(), 404);
    }

    private function forget(User $user): void
    {
        TenantPermissionEvaluator::forgetCacheForUser($user);
        NavigationService::forgetForUser($user);
    }
}
