module transaction.dto;

import handy_http_primitives : Optional;
import asdf : serdeTransformOut;
import std.typecons;

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

/// 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;
    @serdeTransformOut!serializeOptional
    Optional!Vendor vendor;
    @serdeTransformOut!serializeOptional
    Optional!Category category;
    @serdeTransformOut!serializeOptional
    Optional!Account creditedAccount;
    @serdeTransformOut!serializeOptional
    Optional!Account debitedAccount;
    string[] tags;

    static struct Account {
        ulong id;
        string name;
        string type;
        string numberSuffix;
    }

    static struct Vendor {
        ulong id;
        string name;
    }

    static struct Category {
        ulong id;
        string name;
        string color;
    }
}

/// Transaction data provided when fetching a single transaction.
struct TransactionDetail {
    ulong id;
    string timestamp;
    string addedAt;
    ulong amount;
    Currency currency;
    string description;
    bool internalTransfer;
    Nullable!Vendor vendor;
    Nullable!Category category;
    Nullable!Account creditedAccount;
    Nullable!Account debitedAccount;
    string[] tags;
    LineItem[] lineItems;
    AttachmentResponse[] attachments;

    static struct Vendor {
        ulong id;
        string name;
        string description;
    }

    static struct Category {
        ulong id;
        Nullable!ulong parentId;
        string name;
        string description;
        string color;
    }

    static struct LineItem {
        uint idx;
        long valuePerItem;
        ulong quantity;
        string description;
        Nullable!Category category;
    }

    static struct Account {
        ulong id;
        string name;
        string type;
        string numberSuffix;
    }
}

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

    static struct LineItem {
        long valuePerItem;
        ulong quantity;
        string description;
        Nullable!ulong categoryId;
    }
}

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

struct TransactionCategoryResponse {
    ulong id;
    @serdeTransformOut!serializeOptional
    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
        );
    }
}
