package models;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import squirrel.Model;
import squirrel.ModelManager;

import java.security.SecureRandom;
import java.util.Base64;
import java.util.Arrays;
import java.util.Map;
import java.util.List;

public class UserModel extends Model {

    {
        tableName = "users";
        columns.add("id");           
        columns.add("name");         
        columns.add("email");        
        columns.add("password_hash");
    }

    private static final int ITERATIONS = 65536;
    private static final int KEY_LENGTH = 256;

    public UserModel register(String name, String email, String password) {
        if (password == null || password.trim().isEmpty()) {
            throw new IllegalArgumentException("Password cannot be empty");
        }

        UserModel userModel = ModelManager.get(UserModel.class);
        List<UserModel> existingUser = userModel.where(Map.of("email", email));
        if (existingUser != null && !existingUser.isEmpty()) {
            throw new IllegalArgumentException("Email already exists");
        }

        byte[] salt = getSalt();
        UserModel user = new UserModel();

        user.set("name", name);
        user.set("email", email);
        user.set("password_hash", hashPassword(password, salt));
        user.create();
        return user;
    }

    public UserModel authenticate(String email, String password) {
        UserModel userModel = ModelManager.get(UserModel.class);

        List<UserModel> users = userModel.where(Map.of("email", email));
        if (users == null || users.isEmpty()) {
            return null;
        }

        UserModel user = users.get(0);
        String storedHash = (String) user.get("password_hash");
        if (storedHash == null) {
            return null;
        }

        byte[] salt = Base64.getDecoder().decode(storedHash);
        if (!validatePassword(password, storedHash, salt)) {
            return null;
        }

        return user;
    }

    public String hashPassword(String password, byte[] salt) {
        try {
            PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            byte[] hash = skf.generateSecret(spec).getEncoded();
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("Failed to hash password", e);
        }
    }

    public byte[] getSalt() {
        SecureRandom sr = new SecureRandom();
        byte[] salt = new byte[16];
        sr.nextBytes(salt);
        return salt;
    }

    public boolean validatePassword(String password, String storedHash, byte[] salt) {
        try {
            String newHash = hashPassword(password, salt);
            return Arrays.equals(Base64.getDecoder().decode(storedHash), Base64.getDecoder().decode(newHash));
        } catch (Exception e) {
            throw new RuntimeException("Failed to validate password", e);
        }
    }
}
