/// API endpoints for authentication-related functions, like registration and login.
module auth.api;

import handy_http_primitives;
import handy_http_data.json;
import slf4d;

import auth.model;
import auth.data;
import auth.service;
import auth.data_impl_fs;

void postLogin(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    struct LoginData {
        string username;
        string password;
    }
    LoginData data = readJsonBodyAs!LoginData(request);
    string token = generateTokenForLogin(data.username, data.password);
    response.writeBodyString(token);
    infoF!"Generated token for user: %s"(data.username);
}

struct UsernameAvailabilityResponse {
    const bool available;
}

void getUsernameAvailability(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    string username = null;
    foreach (param; request.queryParams) {
        if (param.key == "username" && param.values.length > 0) {
            username = param.values[0];
            break;
        }
    }
    if (username is null || username.length == 0) {
        response.status = HttpStatus.BAD_REQUEST;
        response.writeBodyString("Missing username parameter.");
        return;
    }
    UserRepository userRepo = new FileSystemUserRepository();
    bool available = userRepo.findByUsername(username).isNull;
    writeJsonBody(response, UsernameAvailabilityResponse(available));
}

struct RegistrationData {
    string username;
    string password;
}

void postRegister(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    RegistrationData registrationData = readJsonBodyAs!RegistrationData(request);
    if (!validateUsername(registrationData.username)) {
        response.status = HttpStatus.BAD_REQUEST;
        response.writeBodyString("Invalid username.");
        return;
    }
    if (!validatePassword(registrationData.password)) {
        response.status = HttpStatus.BAD_REQUEST;
        response.writeBodyString("Invalid password.");
        return;
    }
    UserRepository userRepo = new FileSystemUserRepository();
    if (!userRepo.findByUsername(registrationData.username).isNull) {
        response.status = HttpStatus.BAD_REQUEST;
        response.writeBodyString("Username is taken.");
        return;
    }
    
    User user = createNewUser(userRepo, registrationData.username, registrationData.password);
    infoF!"Created user: %s"(registrationData.username);
    response.writeBodyString(user.username);
}

void getMyUser(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    AuthContext auth = getAuthContext(request);
    response.writeBodyString(auth.user.username);
}

void deleteMyUser(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    AuthContext auth = getAuthContext(request);
    UserRepository userRepo = new FileSystemUserRepository();
    deleteUser(auth.user, userRepo);
    infoF!"Deleted user: %s"(auth.user.username);
}

void getNewToken(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    AuthContext auth = getAuthContext(request);
    string token = generateTokenForUser(auth.user);
    response.writeBodyString(token);
    infoF!"Generated token for user: %s"(auth.user.username);
}

struct PasswordChangeRequest {
    string currentPassword;
    string newPassword;
}

void changeMyPassword(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    AuthContext auth = getAuthContext(request);
    PasswordChangeRequest data = readJsonBodyAs!PasswordChangeRequest(request);
    changePassword(auth.user, new FileSystemUserRepository(), data.currentPassword, data.newPassword);
}
