module transaction.dto;

import handy_http_primitives : Optional;
import std.typecons;

import transaction.model : TransactionCategory, TransactionVendor;
import attachment.dto;
import account.dto;
import util.data;
import util.money;

/// A simple selection of vendor data to be included in other responses.
struct SimpleVendorResponse {
    ulong id;
    string name;
}

/// A simple selection of category data to be included in other responses.
struct SimpleCategoryResponse {
    ulong id;
    string name;
    string color;
}

/// Response data for a transaction's line item.
struct TransactionLineItemResponse {
    uint idx;
    long valuePerItem;
    ulong quantity;
    string description;
    Optional!TransactionCategory category;
}

/// The transaction data provided when a list of transactions is requested.
struct TransactionsListItem {
    ulong id;
    string timestamp;
    string addedAt;
    ulong amount;
    Currency currency;
    string description;
    bool internalTransfer;
    Optional!SimpleVendorResponse vendor;
    Optional!SimpleCategoryResponse category;
    Optional!SimpleAccountResponse creditedAccount;
    Optional!SimpleAccountResponse debitedAccount;
    string[] tags;
}

/// Transaction data provided when fetching a single transaction.
struct TransactionDetail {
    ulong id;
    string timestamp;
    string addedAt;
    ulong amount;
    Currency currency;
    string description;
    bool internalTransfer;
    Optional!TransactionVendor vendor;
    Optional!TransactionCategory category;
    Optional!SimpleAccountResponse creditedAccount;
    Optional!SimpleAccountResponse debitedAccount;
    string[] tags;
    TransactionLineItemResponse[] lineItems;
    AttachmentResponse[] attachments;
}

/// Data provided when a new transaction is added by a user.
struct AddTransactionPayload {
    string timestamp;
    ulong amount;
    string currencyCode;
    string description;
    bool internalTransfer;
    Optional!ulong vendorId;
    Optional!ulong categoryId;
    Optional!ulong creditedAccountId;
    Optional!ulong debitedAccountId;
    string[] tags;
    LineItemPayload[] lineItems;
    ulong[] attachmentIdsToRemove;

    static struct LineItemPayload {
        long valuePerItem;
        ulong quantity;
        string description;
        Optional!ulong categoryId;
    }
}

/// Structure for depicting an entire hierarchical tree structure of categories.
struct TransactionCategoryTree {
    ulong id;
    Optional!ulong parentId;
    string name;
    string description;
    string color;
    TransactionCategoryTree[] children;
    uint depth;
}

struct TransactionCategoryResponse {
    ulong id;
    Optional!ulong parentId;
    string name;
    string description;
    string color;

    static TransactionCategoryResponse of(in TransactionCategory category) {
        return TransactionCategoryResponse(
            category.id,
            category.parentId,
            category.name,
            category.description,
            category.color
        );
    }
}

/// Structure representing the balance information for a category, for a given currency.
struct TransactionCategoryBalance {
    ulong credits;
    ulong debits;
    long balance;
    Currency currency;
}

/**
 * A set of aggregate data computed from a set of transactions obtained in a
 * search. Data is grouped by currency.
 */
struct AggregateTransactionData {
    /// Aggregate data about all transactions with a common currency.
    static struct CurrencyData {
        ulong credits;
        ulong debits;
        long balance;
        Currency currency;
    }
    CurrencyData[] currencies;
}

/// Response data for drafts as they'd appear in a list, with less data.
struct TransactionDraftListItem {
    ulong id;
    string addedAt;
    Optional!string templateName;
    Optional!string timestamp;
    Optional!ulong amount;
    Optional!Currency currency;
    Optional!string description;
    Optional!bool internalTransfer;

    Optional!SimpleVendorResponse vendor;
    Optional!SimpleCategoryResponse category;
    Optional!SimpleAccountResponse creditedAccount;
    Optional!SimpleAccountResponse debitedAccount;

    string[] tags;
}

/// Data representing a draft (or template).
struct TransactionDraftResponse {
    ulong id;
    string addedAt;
    Optional!string templateName;
    Optional!string timestamp;
    Optional!ulong amount;
    Optional!Currency currency;
    Optional!string description;
    Optional!bool internalTransfer;

    Optional!SimpleVendorResponse vendor;
    Optional!SimpleCategoryResponse category;
    Optional!SimpleAccountResponse creditedAccount;
    Optional!SimpleAccountResponse debitedAccount;

    string[] tags;
    TransactionLineItemResponse[] lineItems;
    AttachmentResponse[] attachments;
}

/// Data provided by users when creating or updating drafts.
struct TransactionDraftPayload {
    Optional!string templateName;
    Optional!string timestamp;
    Optional!ulong amount;
    Optional!string currencyCode;
    Optional!string description;
    Optional!bool internalTransfer;

    Optional!ulong vendorId;
    Optional!ulong categoryId;
    Optional!ulong creditedAccountId;
    Optional!ulong debitedAccountId;
    
    string[] tags;
    LineItemPayload[] lineItems;
    ulong[] attachmentIdsToRemove;

    static struct LineItemPayload {
        long valuePerItem;
        ulong quantity;
        string description;
        Optional!ulong categoryId;
    }
}

// Recurring Transaction stuff:

struct RecurringTransactionPayload {
    ulong draftId;
    string scheduleExpr;
}

struct RecurringTransactionResponse {
    ulong id;
    ulong draftId;
    string scheduleExpr;
}
