<?php

namespace App\Master;

use App\Exceptions\RoleNotFound;
use App\Notifications\AddedToSiteNotification;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\ModelHasRole;
use Mtc\MercuryDataModels\Role;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\User;

class InviteManager
{
    private string|null $password = null;

    public function invite(string $email, string $siteId, string $role): bool
    {
        if ($this->userAlreadyHasAccess($email, $siteId)) {
            return true;
        }

        /** @var User $user */
        $user = $this->isNewUser($email)
            ? $this->createAccount($email)
            : User::query()->where('email', $email)->first();

        return $this->addUserToSite($user, $siteId, $role);
    }

    private function isNewUser(string $email): bool
    {
        return User::query()
            ->where('email', $email)
            ->exists() == false;
    }

    private function createAccount($email)
    {
        $this->password = Str::random(12);

        return User::query()
            ->create([
                'name' => '',
                'email' => $email,
                'password' => bcrypt($this->password),
            ]);
    }

    private function addUserToSite(User $user, string $siteId, string $role): bool
    {
        $user->tenants()->attach($siteId, ['role' => $role]);
        $roleId = Role::query()->where('name', $role)->first()?->id;
        if (!$roleId) {
            throw new RoleNotFound("$role not found, cannot assign to user");
        }
        ModelHasRole::query()
            ->create([
                'model_type' => 'user',
                'model_id' => $user->id,
                'role_id' => $roleId,
                'tenant_id' => $siteId,
            ]);
        /** @var Tenant $site */
        $site = Tenant::query()->findOrFail($siteId);
        $user->notify(new AddedToSiteNotification($site, $role, $this->password));
        return true;
    }

    private function userAlreadyHasAccess(string $email, string $siteId): bool
    {
        return Tenant::query()
            ->where('id', $siteId)
            ->whereHas('users', function ($userQuery) use ($email) {
                $userQuery->where('email', $email);
            })
            ->exists();
    }
}
