import type { Address, Hex, TypedDataDomain } from 'viem';
import type { SupportedEvmChain } from '../../chains.js';
import { PERMIT2_ADDRESS } from '../../constants.js';

export type TokenPermissions = {
  token: Address;
  amount: bigint;
};

export type TransferData = {
  token: Address;
  receiver: Address;
  amount: bigint;
};

export type CrossChainOrderInfo = {
  user: Address;
  tokenIn: Address;
  srcChainId: number;
  deadline: number;
  amountIn: bigint;
  minStablecoinsAmount: bigint;
  executionDetailsHash: Hex;
  nonce: bigint;
};

export type SingleChainLimitOrder = {
  user: Address;
  tokenIn: Address;
  amountIn: bigint;
  requestedOutput: TransferData;
  extraTransfers: TransferData[];
  encodedExternalCallData: Hex;
  deadline: number;
  nonce: bigint;
};

export type DcaOrderInfo = {
  user: Address;
  tokenIn: Address;
  srcChainId: number;
  startTime: number;
  deadline: number;
  totalIntervals: number;
  intervalDuration: number;
  amountInPerInterval: bigint;
  minStablecoinsAmountPerInterval: bigint;
  executionDetailsHash: Hex;
  nonce: bigint;
};

export type CrossChainPermitTransferFrom = {
  permitted: TokenPermissions;
  spender: Address;
  nonce: bigint;
  deadline: bigint;
  witness: CrossChainOrderInfo;
};

export type SingleChainPermitTransferFrom = {
  permitted: TokenPermissions;
  spender: Address;
  nonce: bigint;
  deadline: bigint;
  witness: SingleChainLimitOrder;
};

export type PermitTransferFrom = CrossChainPermitTransferFrom | SingleChainPermitTransferFrom;

const TOKEN_PERMISSIONS_TYPE = [
  { name: 'token', type: 'address' },
  { name: 'amount', type: 'uint256' },
] as const;

const TRANSFER_DATA_TYPE = [
  { name: 'token', type: 'address' },
  { name: 'receiver', type: 'address' },
  { name: 'amount', type: 'uint256' },
] as const;

// Cross-chain order types
export const CROSS_CHAIN_PERMIT2_TYPES = {
  TokenPermissions: TOKEN_PERMISSIONS_TYPE,
  OrderInfo: [
    { name: 'user', type: 'address' },
    { name: 'tokenIn', type: 'address' },
    { name: 'srcChainId', type: 'uint32' },
    { name: 'deadline', type: 'uint32' },
    { name: 'amountIn', type: 'uint128' },
    { name: 'minStablecoinsAmount', type: 'uint128' },
    { name: 'executionDetailsHash', type: 'bytes32' },
    { name: 'nonce', type: 'uint256' },
  ],
  PermitWitnessTransferFrom: [
    { name: 'permitted', type: 'TokenPermissions' },
    { name: 'spender', type: 'address' },
    { name: 'nonce', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
    { name: 'witness', type: 'OrderInfo' },
  ],
} as const;

// Single-chain limit order types
export const SINGLE_CHAIN_LIMIT_PERMIT2_TYPES = {
  TokenPermissions: TOKEN_PERMISSIONS_TYPE,
  TransferData: TRANSFER_DATA_TYPE,
  SingleChainLimitOrder: [
    { name: 'user', type: 'address' },
    { name: 'tokenIn', type: 'address' },
    { name: 'amountIn', type: 'uint256' },
    { name: 'requestedOutput', type: 'TransferData' },
    { name: 'extraTransfers', type: 'TransferData[]' },
    { name: 'encodedExternalCallData', type: 'bytes' },
    { name: 'deadline', type: 'uint32' },
    { name: 'nonce', type: 'uint256' },
  ],
  PermitWitnessTransferFrom: [
    { name: 'permitted', type: 'TokenPermissions' },
    { name: 'spender', type: 'address' },
    { name: 'nonce', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
    { name: 'witness', type: 'SingleChainLimitOrder' },
  ],
} as const;

export const PERMIT2_DOMAIN = (chainId: SupportedEvmChain): TypedDataDomain => ({
  name: 'Permit2',
  chainId,
  verifyingContract: PERMIT2_ADDRESS[chainId],
});
