import { BigNumber } from "bignumber.js";

/**
 * Memo field type configuration
 */
export type MemoType =
  | "text" // Simple text memo (cosmos, solana, algorand)
  | "tag" // Numeric tag (xrp destination tag, casper transfer id)
  | "typed"; // Typed memo with predefined options (stellar)

/**
 * Input field types for descriptors
 */
export type InputFieldType = "text" | "number" | "tag" | "typed";

/**
 * Input field descriptor for a transaction flow
 */
export type InputDescriptor = Readonly<{
  type: InputFieldType;
  maxLength?: number;
  maxValue?: number;
  options?: readonly string[];
  defaultOption?: string;
  supportsDomain?: boolean; // Whether the field supports domain names (ENS for EVM)
}>;

/**
 * Descriptor for a single custom fee input field
 */
export type CustomFeeInputDescriptor = Readonly<{
  /** Transaction field key, eg. "maxFeePerGas", "feePerByte" */
  key: string;
  /** Input type (currently only "number") */
  type: "number";
  /** Display unit for the input, e.g. "Gwei", "sat/vbyte". Omit for unitless fields (e.g. gas limit). */
  unitLabel?: string;
  /** Optional suggested range displayed below the input */
  suggestedRange?: {
    getRange: (transaction: unknown) => { min: string; max: string } | null;
  };
  /** Optional helper info displayed below the input (e.g. "Next block: 0 Gwei") */
  helperInfo?: {
    getValue: (transaction: unknown) => string | null;
  };
  /** Optional minimum value constraint (e.g. system-estimated gas limit) */
  minValue?: {
    getValue: (transaction: unknown) => string | null;
  };
}>;

/**
 * Configuration for custom fee inputs.
 * Describes which fields to render and how to read/write transaction values.
 */
export type CustomFeeConfig = Readonly<{
  /** List of input fields to render in the custom fees dialog */
  inputs: readonly CustomFeeInputDescriptor[];
  /** Extract initial values from the current transaction */
  getInitialValues: (transaction: unknown) => Record<string, string>;
  /** Build a transaction patch from the user-entered values */
  buildTransactionPatch: (values: Record<string, string>) => Record<string, unknown>;
}>;

/**
 * Option for a fee-paying asset (for Celo WIP)
 */
export type FeeAssetOption = Readonly<{
  id: string;
  ticker: string;
  label: string;
  /** Unit label to display in the fee input when this asset is selected (ex: "Gwei", "sat") */
  unitLabel?: string;
}>;

/**
 * Configuration for coins that support paying fees with alternative assets/tokens.
 */
export type FeeAssetsConfig = Readonly<{
  options: readonly FeeAssetOption[];
  defaultId: string;
}>;

export type FeePresetOption = Readonly<{
  id: string;
  amount: BigNumber;
  estimatedMs?: number;
  disabled?: boolean;
}>;

/**
 * Fee input options
 */
export type FeeDescriptor = {
  hasPresets: boolean;
  hasCustom: boolean;
  hasCustomAssets?: boolean;
  hasCoinControl?: boolean;
  presets?: {
    /**
     * Optional UI legend for presets (ex: fee rate like `2 sat/vbyte`).
     * Descriptor describes how to display it; UI layer provides the actual values (from presetAmount).
     */
    legend?: {
      type: "none" | "feeRate";
      unit: string;
      valueFrom: "presetAmount";
    };
    /**
     * Controls how the selected preset is labeled in the Amount row.
     * - i18n: `Slow/Medium/Fast` via translations
     * - legend: use the computed preset legend (ex: `2 sat/vbyte`)
     */
    strategyLabelInAmount?: "i18n" | "legend";

    /**
     * Optional builder for fee preset options. This allows coin-specific logic
     * to live in descriptors instead of UI-level `family` checks.
     */
    getOptions?: (transaction: unknown) => readonly FeePresetOption[];

    /**
     * Whether fiat estimation for presets should be done via bridge estimation
     * (`prepareTransaction` + `getTransactionStatus`) instead of using `presetAmount` directly.
     */
    shouldEstimateWithBridge?: (transaction: unknown) => boolean;
  };
  /**
   * Configuration for custom fee inputs.
   * When `hasCustom` is true, this describes which input fields to show
   * in the Custom Fees dialog and how to map them to transaction fields.
   */
  custom?: CustomFeeConfig;
  /**
   * Configuration for fee asset selection.
   * When `hasCustomAssets` is true, this describes which assets can be used
   * to pay transaction fees (e.g. Celo's cUSD, cEUR).
   * (Not yet implemented)
   */
  customAssets?: FeeAssetsConfig;
};

export type SendAmountDescriptor = Readonly<{
  /**
   * Optional list of plugins that should run on the Amount step.
   * These are executed by the UI layer through a plugin registry.
   */
  getPlugins?: () => readonly string[];
  canSendMax?: boolean;
}>;

/**
 * Self-transfer policy for a coin
 */
export type SelfTransferPolicy = "free" | "warning" | "impossible";

/**
 * Error registry for coin-specific error classes
 */
export type ErrorRegistry = {
  userRefusedTransaction?: string; // Error class name for when user refuses transaction on device
};

/**
 * Send flow descriptor defining inputs for the send transaction
 */
export type SendDescriptor = {
  inputs: {
    recipientSupportsDomain?: boolean; // Whether recipient field supports domain names (ENS for EVM)
    memo?: InputDescriptor;
  };
  fees: FeeDescriptor;
  amount?: SendAmountDescriptor;
  selfTransfer?: SelfTransferPolicy; // Policy for sending to self (same address), defaults to "impossible"
  errors?: ErrorRegistry; // Registry of error class names for this coin
};

/**
 * Complete flow descriptors for a coin
 */
export type CoinDescriptor = {
  send: SendDescriptor;
  // Future: stake, swap, etc.
};
