import { BigNumber } from "bignumber.js";
import {
  InvalidAddress,
  InvalidAddressBecauseDestinationIsAlsoSource,
  NotEnoughBalance,
  AmountRequired,
  RecommendUndelegation,
} from "@ledgerhq/errors";
import invariant from "invariant";
import type { CosmosAccount, Transaction } from "@ledgerhq/coin-cosmos/types/index";
import { AccountRaw, CurrenciesData } from "@ledgerhq/types-live";
import { fromTransactionRaw } from "@ledgerhq/coin-cosmos/transaction";
import { CosmosTooManyRedelegations } from "@ledgerhq/coin-cosmos/errors";
import { COSMOS_MAX_REDELEGATIONS } from "@ledgerhq/coin-cosmos/logic";

const dataset: CurrenciesData<Transaction> = {
  FIXME_ignoreAccountFields: ["cosmosResources", "operationsCount", "operations"],
  FIXME_ignorePreloadFields: ["validators"], // the APY of validators changes over time
  scanAccounts: [
    {
      name: "cosmos seed 1",
      apdus: `
      => 550400001b06636f736d6f732c00008076000080000000800000000000000000
      <= 0388459b2653519948b12492f1a0b464720110c147a8155d23d423a5cc3c21d89a636f736d6f73316738343933346a70753376356465357971756b6b6b68786d63767377337532616a787670646c9000
      => 550400001b06636f736d6f732c00008076000080000000800000000000000000
      <= 0388459b2653519948b12492f1a0b464720110c147a8155d23d423a5cc3c21d89a636f736d6f73316738343933346a70753376356465357971756b6b6b68786d63767377337532616a787670646c9000
      => 550400001b06636f736d6f732c00008076000080010000800000000000000000
      <= 02624ac83690d5ef627927104767d679aef73d3d3c9544abe4206b1d0c463c94ff636f736d6f7331303875793571396a743539677775677135797264686b7a6364396a7279736c6d706373746b359000
      => 550400001b06636f736d6f732c00008076000080020000800000000000000000
      <= 038ff98278402aa3e46ccfd020561dc9724ab63d7179ca507c8154b5257c7d5200636f736d6f733163676336393661793270673664346763656a656b3279386c6136366a376535793363376b79779000
      => 550400001b06636f736d6f732c00008076000080030000800000000000000000
      <= 02ecca2a8c647b50bcea2cb4667bb8b2c5f5b2b8439d51c842bc9fd20c4185a95c636f736d6f73313474673476736430713734356678687a6e333239706b78306b727174737a6378797a6c356b759000
      => 550400001b06636f736d6f732c00008076000080040000800000000000000000
      <= 03f9f9ddeefd1b762648af6b3ba3e14b0054d7137cf5ed67f501f01524a773c8d0636f736d6f733138713661643239346477357766376e7565713763746c656568786839666774386463656372399000
      => 550400001b06636f736d6f732c00008076000080050000800000000000000000
      <= 03b036c68d156c82e550bf5c0b015313221d618cf4022b96d23f1b559b557ed3ef636f736d6f7331756833396a7830647661387570767171716836393072687432766e36387a7439776d6d6871349000
      `,
    },
  ],
  accounts: [
    {
      FIXME_tests: ["balance is sum of ops"],
      raw: {
        id: "libcore:1:cosmos:cosmospub1addwnpepqwyytxex2dgejj93yjf0rg95v3eqzyxpg75p2hfr6s36tnpuy8vf5p6kez4:",
        seedIdentifier: "0388459b2653519948b12492f1a0b464720110c147a8155d23d423a5cc3c21d89a",
        xpub: "cosmospub1addwnpepqwyytxex2dgejj93yjf0rg95v3eqzyxpg75p2hfr6s36tnpuy8vf5p6kez4",
        derivationMode: "",
        index: 0,
        freshAddress: "cosmos1g84934jpu3v5de5yqukkkhxmcvsw3u2ajxvpdl",
        freshAddressPath: "44'/118'/0'/0/0",
        name: "Cosmos 1",
        balance: "2180673",
        spendableBalance: "2180673",
        blockHeight: 1615299,
        currencyId: "cosmos",
        operationsCount: 85,
        operations: [],
        pendingOperations: [],
        lastSyncDate: "",
      },
      transactions: [
        {
          name: "Same as Recipient",
          transaction: t => ({
            ...t,
            amount: new BigNumber(100),
            recipient: "cosmos1g84934jpu3v5de5yqukkkhxmcvsw3u2ajxvpdl",
          }),
          expectedStatus: {
            errors: {
              recipient: new InvalidAddressBecauseDestinationIsAlsoSource(),
            },
            warnings: {},
          },
        },
        {
          name: "Invalid Address",
          transaction: t => ({
            ...t,
            amount: new BigNumber(100),
            recipient: "dsadasdasdasdas",
          }),
          expectedStatus: {
            errors: {
              recipient: new InvalidAddress(),
            },
            warnings: {},
          },
        },
        {
          name: "send max",
          transaction: fromTransactionRaw({
            amount: "0",
            recipient: "cosmos108uy5q9jt59gwugq5yrdhkzcd9jryslmpcstk5",
            useAllAmount: true,
            family: "cosmos",
            networkInfo: null,
            validators: [],
            sourceValidator: null,
            fees: null,
            gas: null,
            memo: null,
            mode: "send",
          }),
          expectedStatus: (account, t) => {
            const { cosmosResources } = account as CosmosAccount;
            if (!cosmosResources) throw new Error("Should exist because it's cosmos");
            const estimatedFees = t.fees || new BigNumber(0);
            const spendableBalance = account.balance.minus(
              cosmosResources.unbondingBalance.plus(cosmosResources.delegatedBalance),
            );
            const amount = BigNumber.max(0, spendableBalance.minus(estimatedFees));
            const totalSpent = amount.plus(estimatedFees);
            const errors: Record<string, Error> = {};
            const warnings: Record<string, Error> = {};
            if (amount.lte(0)) {
              errors.amount = new NotEnoughBalance();
            }
            if (cosmosResources.delegations.length > 0) {
              warnings.amount = new RecommendUndelegation();
            }
            return {
              errors,
              warnings,
              totalSpent,
            };
          },
        },
        {
          name: "send with memo",
          transaction: fromTransactionRaw({
            amount: "0",
            recipient: "cosmos108uy5q9jt59gwugq5yrdhkzcd9jryslmpcstk5",
            useAllAmount: true,
            family: "cosmos",
            networkInfo: null,
            validators: [],
            sourceValidator: null,
            fees: null,
            gas: null,
            memo: "test",
            mode: "send",
          }),
          expectedStatus: (account, t) => {
            const { cosmosResources } = account as CosmosAccount;
            if (!cosmosResources) throw new Error("Should exist because it's cosmos");
            invariant(t.memo === "test", "Should have a memo");
            const estimatedFees = t.fees || new BigNumber(0);
            const spendableBalance = account.balance.minus(
              cosmosResources.unbondingBalance.plus(cosmosResources.delegatedBalance),
            );
            const amount = BigNumber.max(0, spendableBalance.minus(estimatedFees));
            const totalSpent = amount.plus(estimatedFees);
            const errors: Record<string, Error> = {};
            const warnings: Record<string, Error> = {};
            if (amount.lte(0)) {
              errors.amount = new NotEnoughBalance();
            }
            if (cosmosResources.delegations.length > 0) {
              warnings.amount = new RecommendUndelegation();
            }
            return {
              errors,
              warnings,
              totalSpent,
            };
          },
        },
        {
          name: "Not Enough balance",
          transaction: t => ({
            ...t,
            amount: new BigNumber("99999999999999999"),
            recipient: "cosmos108uy5q9jt59gwugq5yrdhkzcd9jryslmpcstk5",
          }),
          expectedStatus: {
            errors: {
              amount: new NotEnoughBalance(),
            },
            warnings: {},
          },
        },
        {
          name: "Redelegation - success",
          transaction: t => ({
            ...t,
            amount: new BigNumber(100),
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(100),
              },
            ],
            sourceValidator: "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs",
            mode: "redelegate",
          }),
          expectedStatus: (a, t) => {
            invariant(t.memo === "Ledger Live", "Should have a memo");
            const { cosmosResources } = a as CosmosAccount;
            const errors: Record<string, Error> = {};
            if (
              cosmosResources &&
              cosmosResources.redelegations.length >= COSMOS_MAX_REDELEGATIONS
            ) {
              errors.redelegation = new CosmosTooManyRedelegations();
            }
            return {
              errors,
              warnings: {},
            };
          },
        },
        {
          name: "redelegation - AmountRequired",
          transaction: t => ({
            ...t,
            mode: "redelegate",
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(0),
              },
            ],
            sourceValidator: "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs",
          }),
          expectedStatus: a => {
            const { cosmosResources } = a as CosmosAccount;
            const errors: Record<string, Error> = {};
            if (
              cosmosResources &&
              cosmosResources.redelegations.length >= COSMOS_MAX_REDELEGATIONS
            ) {
              errors.redelegation = new CosmosTooManyRedelegations();
            } else {
              errors.amount = new AmountRequired();
            }
            return {
              errors,
              warnings: {},
            };
          },
        },
        {
          name: "redelegation - Source is Destination",
          transaction: t => ({
            ...t,
            mode: "redelegate",
            validators: [
              {
                address: "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs",
                amount: new BigNumber(100),
              },
            ],
            sourceValidator: "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs",
          }),
          expectedStatus: a => {
            const { cosmosResources } = a as CosmosAccount;
            const errors: Record<string, Error> = {};
            if (
              cosmosResources &&
              cosmosResources.redelegations.length >= COSMOS_MAX_REDELEGATIONS
            ) {
              errors.redelegation = new CosmosTooManyRedelegations();
            } else {
              errors.redelegation = new InvalidAddressBecauseDestinationIsAlsoSource();
            }
            return {
              errors,
              warnings: {},
            };
          },
        },
        {
          name: "Unbonding - success",
          transaction: t => ({
            ...t,
            mode: "undelegate",
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(100),
              },
            ],
          }),
          expectedStatus: (a, t) => {
            invariant(t.memo === "Ledger Live", "Should have a memo");
            return {
              errors: {},
              warnings: {},
            };
          },
        },
        {
          name: "Unbonding - AmountRequired",
          transaction: t => ({
            ...t,
            mode: "undelegate",
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(0),
              },
            ],
          }),
          expectedStatus: {
            errors: {
              amount: new AmountRequired(),
            },
            warnings: {},
          },
        },
        {
          name: "Delegate - success",
          transaction: t => ({
            ...t,
            mode: "delegate",
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(100),
              },
            ],
          }),
          expectedStatus: (a, t) => {
            invariant(t.memo === "Ledger Live", "Should have a memo");
            return {
              errors: { amount: new AmountRequired() },
              warnings: {},
            };
          },
        },
        {
          name: "Delegate - not a valid",
          transaction: t => ({
            ...t,
            mode: "delegate",
            validators: [
              {
                address: "cosmos108uy5q9jt59gwugq5yrdhkzcd9jryslmpcstk5",
                amount: new BigNumber(100),
              },
            ],
          }),
          expectedStatus: {
            errors: {
              recipient: new InvalidAddress(),
            },
            warnings: {},
          },
        },
        {
          name: "ClaimReward - success",
          transaction: t => ({
            ...t,
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(0),
              },
            ],
            mode: "claimReward",
          }),
          expectedStatus: (a, t) => {
            invariant(t.memo === "Ledger Live", "Should have a memo");
            return {
              errors: {},
              warnings: {},
            };
          },
        },
        {
          name: "ClaimReward - not a cosmosvaloper",
          transaction: t => ({
            ...t,
            validators: [
              {
                address: "cosmos108uy5q9jt59gwugq5yrdhkzcd9jryslmpcstk5",
                amount: new BigNumber(0),
              },
            ],
            mode: "claimReward",
          }),
          expectedStatus: {
            errors: {
              recipient: new InvalidAddress(),
            },
            warnings: {},
          },
        },
        {
          name: "claimRewardCompound - success",
          transaction: t => ({
            ...t,
            validators: [
              {
                address: "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7",
                amount: new BigNumber(100),
              },
            ],
            mode: "claimRewardCompound",
          }),
          expectedStatus: (a, t) => {
            invariant(t.memo === "Ledger Live", "Should have a memo");
            return {
              errors: {},
              warnings: {},
            };
          },
        },
      ],
    },
    {
      FIXME_tests: ["balance is sum of ops"],
      raw: {
        id: "libcore:1:cosmos:cosmospub1addwnpepqd3nvwwx39pqqvw88sg409675u6wyt4wtzqyt2t0e9y4629t50cdzftxnvz:",
        seedIdentifier:
          "cosmospub1addwnpepqd3nvwwx39pqqvw88sg409675u6wyt4wtzqyt2t0e9y4629t50cdzftxnvz",
        name: "Cosmos Static Account",
        derivationMode: "",
        index: 0,
        freshAddress: "cosmos10l6h3qw05u7qduqgafj8wlrx3fjhr8523sm0c3",
        freshAddressPath: "44'/118'/0'/0/0",
        blockHeight: 2220318,
        creationDate: "2020-04-01T13:51:08.000Z",
        operationsCount: 0,
        operations: [],
        pendingOperations: [],
        currencyId: "cosmos",
        lastSyncDate: "2020-06-11T07:44:10.266Z",
        balance: "1000000",
        spendableBalance: "0",
        xpub: "cosmospub1addwnpepqd3nvwwx39pqqvw88sg409675u6wyt4wtzqyt2t0e9y4629t50cdzftxnvz",
        cosmosResources: {
          delegations: [],
          redelegations: [],
          unbondings: [],
          delegatedBalance: "0",
          pendingRewardsBalance: "0",
          unbondingBalance: "1000000",
          withdrawAddress: "",
        },
      } as AccountRaw,
    },
  ],
};

export default dataset;
