<?php

declare(strict_types=1);

final class User extends MySqlTable implements JsonSerializable
{
    public const FIELD_ID = 'UserId';
    public const FIELD_USERNAME = 'Username';
    public const FIELD_PASSWORD = 'Password';
    public const FIELD_EMAIL = 'Email';
    public const FIELD_JABBER_ADDRESS = 'JabberAddress';

    public function __construct($id = null, DatabaseInterface &$database = null)
    {
        parent::__construct(self::class, $id, $database);
    }

    public function getUserId(): ?int
    {
        if ($this->getPrimaryKey() === null) {
            return null;
        }

        return (int)$this->getPrimaryKey();
    }

    public function getUsername(): string
    {
        return $this->getField(self::FIELD_USERNAME);
    }

    public function getPassword(): string
    {
        return $this->getField(self::FIELD_PASSWORD);
    }

    public function getEmail(): string
    {
        return $this->getField(self::FIELD_EMAIL);
    }

    public function getJabberAddress(): string
    {
        return $this->getField(self::FIELD_JABBER_ADDRESS);
    }

    public function setUsername(string $username): void
    {
        $this->setField(self::FIELD_USERNAME, $username);
    }

    public function setPassword(string $password): void
    {
        $this->setField(self::FIELD_PASSWORD, $password);
    }

    public function setEmail(string $email): void
    {
        $this->setField(self::FIELD_EMAIL, $email);
    }

    public function setJabberAddress(string $jabberAddress): void
    {
        $this->setField(self::FIELD_JABBER_ADDRESS, $jabberAddress);
    }

    public static function getFromUsername(string $username, DatabaseInterface &$database = null): self
    {
        $databaseGiven = true;

        if ($database === null) {
            $database = new MySqlDatabase();
            $databaseGiven = false;
        }

        if ($database->Count(self::class, [self::FIELD_USERNAME => $username]) === 0) {
            throw new UserException(sprintf('No user with name %s found!', $username));
        }

        $id = $database->Select(self::class, [self::FIELD_ID], [self::FIELD_USERNAME => $username])[0][self::FIELD_ID];

        $user = $databaseGiven ? new User((int)$id, $database) : new User((int)$id);

        return $user;
    }

    public static function getFromEmail(string $email, DatabaseInterface &$database = null): self
    {
        $databaseGiven = true;

        if ($database === null) {
            $database = new MySqlDatabase();
            $databaseGiven = false;
        }

        if ($database->Count(self::class) === 0) {
            throw new UserException(sprintf('No user with email %s found!', $email));
        }

        $id = $database->Select(self::class, [self::FIELD_ID], [self::FIELD_EMAIL => $email])[0][self::FIELD_ID];

        $user = $databaseGiven ? new User((int)$id, $database) : new User((int)$id);

        return $user;
    }

    public function getFingerprintIds(): array
    {
        $result = $this->database->Select(
            Fingerprint::class,
            [Fingerprint::FIELD_ID],
            [Fingerprint::FIELD_USER => $this->getUserId()]
        );

        $ids = [];

        foreach ($result as $record) {
            $ids[] = (int)$record[Fingerprint::FIELD_ID];
        }

        return $ids;
    }

    public function jsonSerialize()
    {
        return [
            'userId' => $this->getUserId(),
            'username' => $this->getUsername(),
            'jabberAddress' => $this->getJabberAddress(),
            'fingerprintIds' => $this->getFingerprintIds()
        ];
    }
}