/**
 * This module defines the API endpoints for dealing with Accounts directly,
 * including any data-transfer objects that are needed.
 */
module account.api;

import handy_http_primitives;
import handy_http_data.json;
import handy_http_handlers.path_handler;

import profile.service;
import account.model;
import util.money;
import account.data;

/// The data the API provides for an Account entity.
struct AccountResponse {
    ulong id;
    string createdAt;
    bool archived;
    string type;
    string numberSuffix;
    string name;
    string currency;
    string description;

    static AccountResponse of(in Account account) {
        AccountResponse r;
        r.id = account.id;
        r.createdAt = account.createdAt.toISOExtString();
        r.archived = account.archived;
        r.type = account.type.id;
        r.numberSuffix = account.numberSuffix;
        r.name = account.name;
        r.currency = account.currency.code.dup;
        r.description = account.description;
        return r;
    }
}

void handleGetAccounts(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    import std.algorithm;
    import std.array;
    auto ds = getProfileDataSource(request);
    auto accounts = ds.getAccountRepository().findAll()
        .map!(a => AccountResponse.of(a)).array;
    writeJsonBody(response, accounts);
}

void handleGetAccount(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    ulong accountId = request.getPathParamAs!ulong("accountId");
    auto ds = getProfileDataSource(request);
    auto account = ds.getAccountRepository().findById(accountId)
        .orElseThrow(() => new HttpStatusException(HttpStatus.NOT_FOUND));
    writeJsonBody(response, AccountResponse.of(account));
}

// The data provided by a user to create a new account.
struct AccountCreationPayload {
    string type;
    string numberSuffix;
    string name;
    string currency;
    string description;
}

void handleCreateAccount(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    auto ds = getProfileDataSource(request);
    AccountCreationPayload payload = readJsonBodyAs!AccountCreationPayload(request);
    // TODO: Validate the account creation payload.
    AccountType type = AccountType.fromId(payload.type);
    Currency currency = Currency.ofCode(payload.currency);
    Account account = ds.getAccountRepository().insert(
        type,
        payload.numberSuffix,
        payload.name,
        currency,
        payload.description
    );
    writeJsonBody(response, AccountResponse.of(account));
}

void handleUpdateAccount(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    ulong accountId = request.getPathParamAs!ulong("accountId");
    AccountCreationPayload payload = readJsonBodyAs!AccountCreationPayload(request);
    auto ds = getProfileDataSource(request);
    AccountRepository repo = ds.getAccountRepository();
    auto account = repo.findById(accountId).orElseThrow(() => new HttpStatusException(HttpStatus.NOT_FOUND));
    Account updated = repo.update(accountId, Account(
        account.id,
        account.createdAt,
        account.archived,
        AccountType.fromId(payload.type),
        payload.numberSuffix,
        payload.name,
        Currency.ofCode(payload.currency),
        payload.description
    ));
    writeJsonBody(response, AccountResponse.of(updated));
}

void handleDeleteAccount(ref ServerHttpRequest request, ref ServerHttpResponse response) {
    ulong accountId = request.getPathParamAs!ulong("accountId");
    auto ds = getProfileDataSource(request);
    ds.getAccountRepository().deleteById(accountId);
}
