export interface IDapiConfigurations {
  endpoints?: Map<DapiEndpoint, string>;
  endPointExtraQueryItems?: Map<DapiEndpoint, IDapiQueryParameter[]>;
  endPointExtraHeaderFields?: Map<DapiEndpoint, Map<string, string>>;

  /**
  * Let's you append extra json object to the root of the body.
  * The appended dictionary will be under the key "UserExtraBody" at the root JSON body.
  */
  endPointExtraBody?: Map<DapiEndpoint, Map<string, any>>;

  /**
   * Environment of the banks (either production or sandbox).
   */
  environment?: DapiEnvironment;

  /**
   * Country codes of supported countries. (ISO 3166-2 format)
   */
  countries?: string[];

  /**
   * Controls whether bank account connect UI shows the bank logos.
   * The value is true by default.
   */
  showLogos?: boolean;

  /**
   * Controls whether bank account connect UI shows a close button.
   * The value is true by default.
   */
  showCloseButton?: boolean;

  /**
   * Controls whether account selection UI shows a add account button.
   * The value is true by default.
   */
  showAddButton?: boolean;

  showTransferSuccessfulResult?: boolean;

  showTransferErrorResult?: boolean;

  showExperimentalBanks?: boolean;

  postSuccessfulConnectionLoadingText?: string
}

export enum DapiEnvironment {
  sandbox = 'sandbox',
  production = 'production',
}

export enum DapiEndpoint {
  exchangeToken = 'auth/ExchangeToken',
  getIdentity = 'data/identity/get',
  getAccounts = 'data/accounts/get',
  getAccountMetadata = 'metadata/accounts/get',
  getTransactions = 'data/transactions/get',
  getBeneficiaries = 'payment/beneficiaries/get',
  createBeneficiary = 'payment/beneficiaries/create',
  createTransfer = 'payment/transfer/create',
  createTransferToExistingBeneficiary = 'payment/transfer/autoflow',
  getWireBeneficiaries = 'wire/beneficiaries/get',
  createWireBeneficiary = 'wire/beneficiaries/create',
  createWireTransfer = 'wire/transfer/autoflow',
  createWireTransferToExistingBeneficiary = 'wire/transfer/create',
  delete = 'users/DelinkUser',
}

export interface IDapiQueryParameter {
  name: string;
  value: string;
}

export interface ILineAddress {
  line1: string;
  line2: string;
  line3: string;
}

export interface IBeneficiary {
  linesAddress: ILineAddress;
  accountNumber: string;
  name: string;
  bankName: string;
  swiftCode: string;
  iban: string;
  phoneNumber: string;
  country: string;
  branchAddress: string;
  branchName: string;
  nickname?: string | null;
}

export interface IWireBeneficiary {
  linesAddress: ILineAddress;
  name: string;
  firstName: string;
  lastName: string;
  nickname: string;
  city: string;
  state: string;
  country: string;
  zipCode: string;
  receiverType: string;
  receiverAccountType: string;
  routingNumber: string;
  accountNumber: string;
}

export interface IPair {
  code: string;
  name: string;
}

export interface IAccountResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly accounts: IAccount[];
}

export interface ICardResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly cards: ICard[];
}

export interface ITransferResponse {
  readonly account?: IAccount;
  readonly amount: number;
  readonly operationID: string;
}

export interface IBankBeneficiary {
  readonly name: string;
  readonly iban: string | null;
  readonly accountNumber: string | null;
  readonly status: string | null;
  readonly type: string;
  readonly id: string;
}

export interface IBankBeneficiaryResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly beneficiaries: IBankBeneficiary[];
}

export interface IBankWireBeneficiary {
  readonly name: string;
  readonly accountNumber: string | null;
  readonly status: string | null;
  readonly type: string;
  readonly id: string;
  readonly address: IAddress;
  readonly routingNumbers: string;
}

export interface IBankWireBeneficiaryResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly beneficiaries: IBankWireBeneficiary[];
}

export interface IAccount {
  readonly balance: IAccountBalance;
  readonly iban: string | null;
  readonly number: string | null;
  readonly currency: IPair;
  readonly type: string;
  readonly id: string;
  readonly name: string;
}

export interface IAccountBalance {
  readonly amount: number
}

export interface ICardBalance {
  readonly amountDue: number;
  readonly availableBalance: number;
  readonly outstandingBalance: number;
  readonly dueDate: string;
}

export interface ICard {
  readonly balance: ICardBalance;
  readonly cardNumber: string;
  readonly creditLimit: string;
  readonly currency: IPair;
  readonly expiryDate: string;
  readonly id: string;
  readonly name: string;
  readonly status: string;
  readonly type: string;
}

interface IIdentification {
  type: string;
  value: string;
}

interface IPhoneNumber {
  type: string;
  value: string;
}

interface IAddressGeneral {
  flat: string;
  building: string;
  full: string;
  area: string;
  poBox: string;
  city: string;
  state: string;
  country: string;
}

export interface IIdentityResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly identity: IIdentity;
}

export interface IIdentity {
  readonly nationality: string;
  readonly dateOfBirth: Date;
  readonly numbers: IPhoneNumber[];
  readonly emailAddress: string;
  readonly name: string;
  readonly address: IAddress;
  readonly identification: IIdentification[];
}

export interface IBalance {
  amount: number;
  currency: IPair;
  accountNumber: string;
}

enum TransactionType {
  CREDIT = 'credit',
  DEBIT = 'debit',
}

export interface ITransactionResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly transactions: ITransaction[];
}

export interface ITransaction {
  readonly amount: number;
  readonly date: Date;
  readonly type: TransactionType;
  readonly description: string | null;
  readonly details: string | null;
  readonly currency: IPair;
  readonly beforeAmount: number | null;
  readonly afterAmount: number | null;
  readonly reference?: string | null;
}

export interface IDapiResult {
  readonly operationID: string;
  readonly status: string;
  readonly success: boolean;
  readonly message: string;
}

export enum BeneficiaryType {
  SAME = 'same',
  LOCAL = 'local',
  INTERNATIONAL = 'intl',
  OWN = 'own',
}

export interface ITransferBounds {
  minimum: number;
  currency: IPair;
  type: BeneficiaryType;
}

export interface IAccountsMetadataResponse {
  readonly operationID: string;
  readonly success: boolean;
  readonly accountsMetadata: IAccountsMetadata;
}

export interface IAccountsMetadata {
  readonly swiftCode: string;
  readonly sortCode: string | null;
  readonly bankName: string;
  readonly branchName: string;
  readonly branchAddress: string;
  readonly address: ILineAddress;
  readonly transferBounds: ITransferBounds[];
  readonly beneficiaryCoolDownPeriod: {
    readonly value: number;
    readonly unit: 'hrs';
  };
  readonly transactionRange: {
    readonly unit: 'days';
    readonly value: number;
  };
  readonly country: IPair;
  readonly isCreateBeneficiaryEndpointRequired: boolean;
  readonly willNewlyAddedBeneficiaryExistBeforeCoolDownPeriod: boolean;
}

export interface IDapiConnection {
  readonly clientUserID: string;
  readonly userID: string;
  readonly bankID: string;
  readonly swiftCode: string;
  readonly country: string;
  readonly bankShortName: string;
  readonly bankFullName: string;
  readonly accounts: IAccount[];
  readonly cards: ICard[];
  readonly fullLogo: string;
  readonly halfLogo: string;
  readonly miniLogo: string;


  getIdentity(): Promise<IIdentityResponse>;

  getAccounts(): Promise<IAccountResponse>;

  getCards(): Promise<ICardResponse>;

  getTransactionsForAccount(
    account: IAccount,
    startDate: Date,
    endDate: Date,
  ): Promise<ITransactionResponse>;

  getTransactionsForCard(
    card: ICard,
    startDate: Date,
    endDate: Date,
  ): Promise<ITransactionResponse>;

  getAccountsMetadata(): Promise<IAccountsMetadataResponse>;

  delete(): Promise<void>;

  getBeneficiaries(): Promise<IBankBeneficiaryResponse>;

  createBeneficiary(beneficiary: IBeneficiary): Promise<IDapiResult>;

  createTransfer(
    fromAccount: IAccount | null,
    toBeneficiary: IBeneficiary | null,
    amount: number,
    remark: string | null,
  ): Promise<ITransferResponse>;

  createTransferToExistingBeneficiary(
    fromAccount: IAccount,
    toBeneficiaryID: string,
    amount: number,
    remark: string | null,
  ): Promise<ITransferResponse>;

  createWireTransfer(
    toBeneficiary: IWireBeneficiary,
    fromAccount: IAccount | null,
    amount: number,
    remark: string | null,
  ): Promise<any>;

  createWireTransferToExistingBeneficiary(
    fromAccount: IAccount | null,
    toBeneficiaryID: string,
    amount: number,
    remark: string | null,
  ): Promise<any>;

  getWireBeneficiaries(): Promise<IBankWireBeneficiaryResponse>;

  createWireBeneficiary(beneficiary: IWireBeneficiary): Promise<IDapiResult>;

  getParameters(): Promise<string>
}

export type IAddress = IAddressGeneral;
