/* eslint-disable no-console */
// Decoders for popular Any messages into readable snake_case structures.

import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx.js";
import {
    MsgDelegate,
    MsgUndelegate,
    MsgBeginRedelegate,
} from "cosmjs-types/cosmos/staking/v1beta1/tx.js";
import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx.js";
import { MsgVote } from "cosmjs-types/cosmos/gov/v1/tx.js";
import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx.js";

type AnyMsg = { typeUrl: string; value: Uint8Array };

function coinToSnake(c?: { denom: string; amount: string }) {
    return c ? { denom: c.denom, amount: c.amount } : undefined;
}
function coinsToSnake(cs?: Array<{ denom: string; amount: string }>) {
    return (cs ?? []).map((c) => ({ denom: c.denom, amount: c.amount }));
}

export type DecodedMsgKnown =
    | ReturnType<typeof decodeMsgSend>
    | ReturnType<typeof decodeMsgDelegate>
    | ReturnType<typeof decodeMsgUndelegate>
    | ReturnType<typeof decodeMsgBeginRedelegate>
    | ReturnType<typeof decodeMsgWithdrawDelegatorReward>
    | ReturnType<typeof decodeMsgVote>
    | ReturnType<typeof decodeMsgIbcTransfer>;

function decodeMsgSend(any: AnyMsg) {
    const m = MsgSend.decode(any.value);
    return {
        "@type": any.typeUrl,
        from_address: m.fromAddress,
        to_address: m.toAddress,
        amount: coinsToSnake(m.amount as any),
    };
}
function decodeMsgDelegate(any: AnyMsg) {
    const m = MsgDelegate.decode(any.value);
    return {
        "@type": any.typeUrl,
        delegator_address: m.delegatorAddress,
        validator_address: m.validatorAddress,
        amount: coinToSnake(m.amount as any),
    };
}
function decodeMsgUndelegate(any: AnyMsg) {
    const m = MsgUndelegate.decode(any.value);
    return {
        "@type": any.typeUrl,
        delegator_address: m.delegatorAddress,
        validator_address: m.validatorAddress,
        amount: coinToSnake(m.amount as any),
    };
}
function decodeMsgBeginRedelegate(any: AnyMsg) {
    const m = MsgBeginRedelegate.decode(any.value);
    return {
        "@type": any.typeUrl,
        delegator_address: m.delegatorAddress,
        validator_src_address: m.validatorSrcAddress,
        validator_dst_address: m.validatorDstAddress,
        amount: coinToSnake(m.amount as any),
    };
}
function decodeMsgWithdrawDelegatorReward(any: AnyMsg) {
    const m = MsgWithdrawDelegatorReward.decode(any.value);
    return {
        "@type": any.typeUrl,
        delegator_address: m.delegatorAddress,
        validator_address: m.validatorAddress,
    };
}
function decodeMsgVote(any: AnyMsg) {
    const m = MsgVote.decode(any.value);
    return {
        "@type": any.typeUrl,
        voter: m.voter,
        proposal_id: m.proposalId?.toString() ?? "0",
        option: m.option,
    };
}
function decodeMsgIbcTransfer(any: AnyMsg) {
    const m = MsgTransfer.decode(any.value);
    return {
        "@type": any.typeUrl,
        source_port: m.sourcePort,
        source_channel: m.sourceChannel,
        token: coinToSnake(m.token as any),
        sender: m.sender,
        receiver: m.receiver,
        timeout_height: m.timeoutHeight
            ? {
                revision_number: m.timeoutHeight.revisionNumber?.toString() ?? "0",
                revision_height: m.timeoutHeight.revisionHeight?.toString() ?? "0",
            }
            : undefined,
        timeout_timestamp: m.timeoutTimestamp?.toString() ?? "0",
    };
}

/** Decode known message types; return `null` if type is unknown */
export function decodeKnownAny(any: AnyMsg): DecodedMsgKnown | null {
    switch (any.typeUrl) {
        case "/cosmos.bank.v1beta1.MsgSend":
            return decodeMsgSend(any);
        // case "/cosmos.staking.v1beta1.MsgDelegate":
        //     return decodeMsgDelegate(any);
        // case "/cosmos.staking.v1beta1.MsgUndelegate":
        //     return decodeMsgUndelegate(any);
        // case "/cosmos.staking.v1beta1.MsgBeginRedelegate":
        //     return decodeMsgBeginRedelegate(any);
        // case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward":
        //     return decodeMsgWithdrawDelegatorReward(any);
        // case "/cosmos.gov.v1.MsgVote":
        //     return decodeMsgVote(any);
        // case "/ibc.applications.transfer.v1.MsgTransfer":
        //     return decodeMsgIbcTransfer(any);
        default:
            return null;
    }
}