<?php

namespace Lucent\Account;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Lucent\Primitive\Collection;
use PhpOption\Option;

class UserRepo
{

    public function count(): int
    {
        return DB::table("users")->count();
    }

    /**
     * @return Collection<User>
     */
    public function all(): Collection
    {
        $usersData = DB::table("users")->get();

        $users = array_map(fn($userData) => $this->fromArray((array)$userData), $usersData->toArray());
        return new Collection($users);
    }


    public static function insert(User $user): void
    {
        $userData = toArray($user);
        $userData["roles"] = json_encode($userData["roles"]);
        DB::table("users")->insert($userData);
    }

    public function update(User $user): void
    {
        $userData = toArray($user);
        $userData["roles"] = json_encode($userData["roles"]);
        DB::table("users")->where("id", $user->id)->update($userData);
    }


    public function updateLoginToken(string $id): string
    {
        $newToken = Token::new(32);

        DB::table("users")
            ->where("id", $id)
            ->update([
                'loggedInAt' => Carbon::now()->toJson(),
                'mailToken' => $newToken,
            ]);

        return $newToken;
    }


    /**
     * @return Option<User>
     */
    public function findByEmail(Email $email): Option
    {
        $user = DB::table("users")->where("email", $email->value())->first();

        if (empty($user)) {
            return none();
        }

        return some($this->fromArray((array)$user));
    }

    /**
     * @return Option<User>
     */
    public function findById(string $id): Option
    {
        $user = DB::table("users")->where("id", $id)->first();

        if (empty($user)) {
            return none();
        }

        return some($this->fromArray((array)$user));
    }


    public function updateName(string $userId, Name $name): void
    {
        DB::table("users")->where("id", $userId)->update(["name" => $name->value]);
    }

    public function updateEmail(string $userId, Email $email): void
    {
        DB::table("users")->where("id", $userId)->update(["email" => $email->value()]);
    }

    public function fromArray(array $data): User
    {
        return new User(
            id: $data["id"],
            name: new Name($data["name"] ?? ""),
            email: new Email($data["email"]),
            roles: json_decode($data["roles"] ?? "[]",true),
            createdAt: $data["createdAt"],
            updatedAt: $data["updatedAt"],
            loggedInAt: $data["loggedInAt"] ?? null,
            mailToken: $data["mailToken"] ?? null,
        );
    }
}
