/*
 * Copyright (C) 2025  Tim Zimmermann <tim@aglais.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.aglais.zms.db.core.model;

import at.favre.lib.crypto.bcrypt.BCrypt;

import java.io.Serial;
import java.io.Serializable;

/**
 * Class representing a user
 */
public class User implements Serializable {

    @Serial
    private static final long serialVersionUID = 1;

    private int id;
    private String name;
    private char[] password;

    /**
     * Create a new {@link User} object
     *
     * @param id       User ID as stored in the database
     * @param name     User name
     * @param password User password
     */
    public User(int id, String name, char[] password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }

    /**
     * No-arg constructor for {@link ModifiedStateTracker}. This constructor creates an empty
     * User object that can be populated with data later. It is protected to ensure that only
     * classes within the same package or subclasses can create instances without providing
     * initial data.
     */
    protected User() {

    }

    /**
     * Get the user ID
     *
     * @return ID from Database, <= 0 if not yet stored
     */
    public int getID() {
        return id;
    }

    /**
     * Set the user ID
     *
     * @param id ID from the Database
     */
    public void setID(int id) {
        this.id = id;
    }

    /**
     * Get the username
     *
     * @return Username
     */
    public String getName() {
        return name;
    }

    /**
     * Set the username
     *
     * @param name Username
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Get the hashed password
     *
     * @return User password
     */
    public char[] getPassword() {
        return password;
    }

    /**
     * Set the hashed password
     *
     * @param password User password
     */
    public void setPassword(char[] password) {
        this.password = password;
    }

    /**
     * Try to authenticate the user with the given password
     *
     * @param password The password to use for authentication
     * @return True if the user can successfully authenticate with the given password, false otherwise
     */
    public boolean verifyPassword(String password) {
        return BCrypt.verifyer().verify(password.toCharArray(), this.password).verified;
    }

    /**
     * Set the user's password hash from a given cleartext password
     *
     * @param password The password in cleartext
     */
    public void setClearTextPassword(String password) {
        setPassword(BCrypt.withDefaults().hashToChar(12, password.toCharArray()));
    }
}
