// core/types/interfaces/pipeline.ts
//
// Transaction Pipeline Context Type System
// ========================================
//
// This module defines a 5-phase context type hierarchy for transaction processing:
//
//   Phase 1: IBaseContext      -> Initial input (txBase64, statedb, config, indexdb)
//   Phase 2: IDecodedContext   -> After DecodeTx + DecodeItx (tx, itx, txType, txHash)
//   Phase 3: IGasContext       -> After ExtractState + EnsureTxGas + EnsureTxCost
//   Phase 4: IReadyContext     -> After TakeStateSnapshot, ready for business logic
//   Phase 5: IExecutedContext  -> After business logic execution complete
//
// Protocol-specific states are provided as Mixin interfaces (IWithSender, IWithAsset, etc.)
// that can be combined with phase types to create protocol-specific context types.
//
// Example:
//   type DelegateContext = IReadyContext<TDelegateTx> & IWithSender & IWithReceiver & IWithDelegation;
//

import type { ILedger } from './ledger';

import type { TTokenInput, TTransactionReceipt } from '../lib/type_pb';
import type { BN } from './base';
import type { IAny } from './base';
import type { IChainConfig } from './config';
import type { IIndexDB } from './indexdb';
import type {
  IAccountState,
  IAssetFactoryState,
  IAssetState,
  IDelegateState,
  IEvidenceState,
  IRollupBlock,
  IRollupState,
  IStakeState,
  ITokenFactoryState,
  ITokenState,
  TokenBalanceMap,
} from './state';
import type { IStateDB } from './statedb';

// =============================================================================
// Common Interfaces
// =============================================================================

/** Logger interface for pipeline operations */
export interface IPipelineLogger {
  /** Logger methods accept any arguments for flexible logging */
  debug: (message: string, ...args: unknown[]) => void;
  info: (message: string, ...args: unknown[]) => void;
  warn: (message: string, ...args: unknown[]) => void;
  error: (message: string, ...args: unknown[]) => void;
}

/**
 * Decoded transaction — canonical camelCase shape (Phase 4 decision q11).
 *
 * Repeated fields use the `xxx` name (`signatures`, `tags`, `slashers`). The
 * protobuf-wire `xxxList` alias is an `@ocap/proto/runtime` implementation
 * detail and is not part of this interface. Pipe code still accessing
 * `tx.signaturesList` at runtime (protobuf-decoded txs) falls through the
 * index signature as `unknown`; prefer `getListField(tx, 'signatures')` to
 * read either shape safely.
 */
export interface IDecodedTransaction {
  from: string;
  delegator?: string;
  chainId: string;
  nonce: number;
  serviceFee?: string;
  pk: Uint8Array;
  signature?: Uint8Array | string;
  signatures?: IMultiSigData[];
  itx: IAny;
  /** Index signature for dynamic field access during verification */
  [key: string]: unknown;
}

/** Multi-signature data structure for pipeline (decoded format, not proto) */
export interface IMultiSigData {
  signer: string;
  delegator?: string;
  pk: Uint8Array;
  signature: Uint8Array;
  data?: IAny;
}

/** Account update record */
export interface IAccountUpdate {
  address: string;
  delta?: string;
  token?: string;
  action?: string;
}

/** Locked state for stake verification */
export interface ILockedState {
  address: string;
  tokens: TokenBalanceMap;
  assets: string[];
}

/** Input change tracking for token factory operations */
export interface IInputChange {
  address: string;
  token?: string;
  delta: string;
}

/** Validated inner transaction for delegation */
export interface IValidatedItx {
  opsList?: Array<{
    typeUrl?: string;
    limit?: {
      tokensList?: Array<{
        address?: string;
        txCount?: number;
        txAllowance?: string;
        totalAllowance?: string;
        validUntil?: number;
        rate?: { interval?: number; anchor?: number } | null;
      }>;
      assetsList?: Array<{
        address?: string[];
        txCount?: number;
        validUntil?: number;
        rate?: { interval?: number; anchor?: number } | null;
      }>;
    };
  }>;
}

/** Gas stake configuration */
export interface IGasStake {
  owner?: string;
  stakeId?: string;
  state?: IStakeState | null;
  valid?: boolean;
}

/** Token condition for balance verification */
export interface ITokenCondition {
  owner: string;
  tokens: Array<{ address: string; value: BN }>;
}

/** Output structure for transaction results */
export interface IOutput {
  owner: string;
  tokens?: TTokenInput[];
  assets?: string[];
}

/** Input structure for transaction */
export interface IInput {
  owner: string;
  tokensList?: TTokenInput[];
  assetsList?: string[];
}

// =============================================================================
// Phase 1: Base Context
// =============================================================================

/**
 * Phase 1: Initial input context
 *
 * This is the starting point of the pipeline. Contains only the required
 * inputs provided by the caller before any processing begins.
 *
 * @template TItx - Inner transaction type (default: unknown)
 */
export interface IBaseContext<TItx = unknown> {
  /** Base64 encoded transaction */
  txBase64: string;
  /**
   * Wire encoding detected by `DecodeTx` from the first three bytes of the
   * decoded payload. Downstream pipes (verify-signature, verify-multisig,
   * and tx-protocols' `toItxAddress` call sites) must select the matching
   * serializer. Literal union (not `string`) to catch typos at compile time.
   *
   * Populated by DecodeTx on Phase 1+; optional on `IBaseContext` so the
   * pipeline can still type-check callers that build a bare base context
   * (e.g. test harnesses that exercise DecodeTx first).
   */
  txEncoding?: 'cbor' | 'protobuf';
  /** State database instance */
  statedb: IStateDB;
  /** Chain configuration */
  config: IChainConfig;
  /** Index database instance */
  indexdb: IIndexDB;
  /** Optional logger for pipeline operations */
  logger?: IPipelineLogger;
  /** Extra context data */
  extra?: {
    /** Gas stake headers from HTTP request */
    gasStakeHeaders?: { token?: string; pk?: string };
    /** HTTP request object - format varies by server framework */
    request?: unknown;
    /** Extension point for protocol-specific data */
    [key: string]: unknown;
  };

  // Internal fields that may be set at any phase
  /** Database transaction handle - type depends on StateDB implementation */
  txn?: unknown;
  /** State helper functions - set by execute.ts */
  states?: unknown;
  /** Event queue for indexdb updates */
  events?: Array<{ table: string; name: string; data: unknown; ctx: Record<string, unknown> }>;

  // Type hint for TItx (not used at runtime)
  /** @internal Type parameter placeholder */
  readonly __itxType?: TItx;

  /** Verifiable ledger instance for append-only transaction log */
  ledger: ILedger;

  /** Ledger sequence number (set by WriteLedger pipe, used in Phase 6) */
  ledgerSequence?: number;

  /** Index signature for IOperationContext compatibility and dynamic property access */
  [key: string]: unknown;
}

// =============================================================================
// Phase 1.5: Tx Only Context (intermediate state)
// =============================================================================

/**
 * Intermediate context after DecodeTx but before DecodeItx
 *
 * At this phase, the outer transaction has been decoded but the inner
 * transaction (itx) has not been extracted yet. Used by DecodeItx pipe.
 *
 * Added by: DecodeTx pipe
 */
export interface ITxOnlyContext extends IBaseContext {
  /** Decoded transaction object (itx is still encoded as Any) */
  tx: IDecodedTransaction;
  /** Transaction hash (DID format) */
  txHash: string;
  /** Transaction timestamp (ISO 8601) */
  txTime: string;
  /** Transaction size in bytes */
  txSize: number;
  /** Whether to charge base gas */
  txBaseGas: boolean;
  /**
   * Wire encoding of the transaction. Always populated by `DecodeTx` before
   * any downstream pipe runs, hence required here and inherited by the
   * decoded / gas / ready / executed phases via the extends chain.
   */
  txEncoding: 'cbor' | 'protobuf';
}

// =============================================================================
// Phase 2: Decoded Context
// =============================================================================

/**
 * Phase 2: Context after DecodeTx + DecodeItx
 *
 * At this phase, the transaction has been decoded from base64 and the inner
 * transaction (itx) has been extracted. The transaction can now be routed
 * to the appropriate protocol handler.
 *
 * Added by: DecodeTx, DecodeItx pipes
 *
 * @template TItx - Inner transaction type
 */
export interface IDecodedContext<TItx = unknown> extends ITxOnlyContext {
  /** Decoded inner transaction */
  itx: TItx;
  /** Transaction type URL (e.g., 'fg:t:transfer') */
  txType: string;
}

// =============================================================================
// Phase 3: Gas Context
// =============================================================================

/**
 * Phase 3: Context after Gas calculation
 *
 * At this phase, states have been extracted (ExtractState) and gas/cost
 * calculations are complete (EnsureTxGas, EnsureTxCost). The transaction
 * fees have been calculated and sender updates prepared.
 *
 * Added by: ExtractState, EnsureTxGas, EnsureTxCost pipes
 *
 * @template TItx - Inner transaction type
 */
export interface IGasContext<TItx = unknown> extends IDecodedContext<TItx> {
  /** Total gas consumed (set by EnsureGas pipe) */
  totalGas?: BN;
  /** Gas estimate breakdown (set by EnsureGas pipe) */
  gasEstimate?: { create: number; update: number; payment?: number };
  /** Receipts for balance changes */
  receipts?: TTransactionReceipt[];

  // Fee calculation results
  /** Pending updates to apply to sender account */
  senderUpdates?: Record<string, string>;
  /** Function to update vault balances */
  updateVaults?: () => Promise<void> | void;
  /** Sender balance change record */
  senderChange?: { address: string; token: string; delta: string } | null;

  // Vault configuration (optional - depends on chain config)
  /** Gas vault address */
  gasVault?: string;
  /** Fee vault address */
  feeVault?: string;
  /** Gas stake configuration */
  gasStake?: IGasStake;
  /** Fee vault change record */
  feeVaultChange?: { address: string; value: string };
  /** Gas vault change record */
  gasVaultChange?: { address: string; value: string };

  // Flags
  /** Whether gas has been paid */
  gasPaid?: boolean;
  /** Whether using gas stake */
  isGasStake?: boolean;

  // Account updates (populated by updateVaults callback)
  /** List of account updates applied */
  updatedAccounts?: IAccountUpdate[];
}

// =============================================================================
// Phase 4: Ready Context
// =============================================================================

/**
 * Phase 4: Context ready for business logic execution
 *
 * At this phase, all preparation is complete:
 * - Transaction decoded
 * - States extracted
 * - Gas calculated
 * - State snapshot taken
 *
 * This is the input type for protocol-specific business logic pipes.
 * Combine with Mixin interfaces to create protocol-specific context types.
 *
 * Added by: TakeStateSnapshot pipe
 *
 * @template TItx - Inner transaction type
 *
 * @example
 * ```typescript
 * // Define protocol-specific context
 * type DelegateContext = IReadyContext<TDelegateTx>
 *   & IWithSender
 *   & IWithReceiver
 *   & Partial<IWithDelegation>;
 *
 * // Use in business logic pipe
 * runner.use(async (context: DelegateContext, next) => {
 *   const { senderState, receiverState, delegationState } = context;
 *   // ... business logic
 * });
 * ```
 */
export interface IReadyContext<TItx = unknown> extends IGasContext<TItx> {
  // Vault states (extracted by TakeStateSnapshot if configured)
  /** Fee vault account state */
  feeVaultState?: IAccountState;
  /** Gas vault account state */
  gasVaultState?: IAccountState;
}

// =============================================================================
// Phase 5: Executed Context
// =============================================================================

/**
 * Phase 5: Context after business logic execution
 *
 * At this phase, the business logic has completed and all state
 * modifications have been applied. Ready for final verification
 * (VerifyStateDiff) and transaction persistence.
 *
 * @template TItx - Inner transaction type
 */
export interface IExecutedContext<TItx = unknown> extends IReadyContext<TItx> {
  /** List of account updates applied - required at this phase */
  updatedAccounts: IAccountUpdate[];
}

// =============================================================================
// Mixin Interfaces: Account States
// =============================================================================

/** Mixin: Sender account state is required */
export interface IWithSender {
  senderState: IAccountState;
}

/** Mixin: Receiver account state is required */
export interface IWithReceiver {
  receiverState: IAccountState;
}

/** Mixin: Delegator account state is required */
export interface IWithDelegator {
  delegatorState: IAccountState;
}

/** Mixin: Multiple delegator account states are required */
export interface IWithDelegators {
  delegatorStates: IAccountState[];
}

/** Mixin: Owner account state is required */
export interface IWithOwner {
  ownerState: IAccountState;
  ownerAddress: string;
}

/** Mixin: Issuer account state is required */
export interface IWithIssuer {
  issuerState: IAccountState;
}

/** Mixin: Multiple issuer account states are required */
export interface IWithIssuers {
  issuerStates: IAccountState[];
}

/** Mixin: Locker account state is required */
export interface IWithLocker {
  lockerState: IAccountState;
  lockerAddress: string;
}

/** Mixin: Multiple signer states are required */
export interface IWithSigners {
  signerStates: IAccountState[];
  signers: string[];
}

/** Mixin: Multiple receiver states are required */
export interface IWithReceivers {
  receiverStates: IAccountState[];
  receivers: string[];
}

/** Mixin: Multiple sender states are required */
export interface IWithSenders {
  senderStates: IAccountState[];
  senders: string[];
}

// =============================================================================
// Mixin Interfaces: Protocol States
// =============================================================================

/** Mixin: Asset state is required */
export interface IWithAsset {
  assetState: IAssetState;
}

/** Mixin: Multiple asset states are required */
export interface IWithAssets {
  assetStates: IAssetState[];
}

/** Mixin: Token state is required */
export interface IWithToken {
  tokenState: ITokenState;
  tokenAddress: string;
}

/** Mixin: Multiple token states are required */
export interface IWithTokens {
  tokenStates: ITokenState[];
}

/** Mixin: Asset factory state is required */
export interface IWithFactory {
  factoryState: IAssetFactoryState;
}

/** Mixin: Token factory state is required */
export interface IWithTokenFactory {
  tokenFactoryState: ITokenFactoryState;
}

/** Mixin: Stake state is required */
export interface IWithStake {
  stakeState: IStakeState;
  stakeAddress: string;
}

/** Mixin: Multiple stake states are required */
export interface IWithStakes {
  stakeStates: IStakeState[];
}

/** Mixin: Delegation state is required */
export interface IWithDelegation {
  delegationState: IDelegateState;
}

/** Mixin: Rollup state is required */
export interface IWithRollup {
  rollupState: IRollupState;
}

/** Mixin: Rollup block state is required */
export interface IWithRollupBlock {
  rollupBlockState: IRollupState;
  blockState: IRollupBlock;
}

/** Mixin: Evidence state is required */
export interface IWithEvidence {
  evidenceState: IEvidenceState;
}

/** Mixin: Locked state is required (for stake operations) */
export interface IWithLocked {
  lockedState: ILockedState;
}

/** FinalizedContext uses unknown for TItx as it represents any possible inner transaction type */
export type FinalizedContext = IExecutedContext<unknown> &
  IWithSender &
  IWithSenders &
  IWithSigners &
  IWithReceiver &
  IWithReceivers &
  IWithDelegator &
  IWithDelegators &
  IWithOwner &
  IWithIssuer &
  IWithIssuers &
  IWithLocker &
  IWithDelegation &
  IWithAsset &
  IWithAssets &
  IWithToken &
  IWithTokens &
  IWithFactory &
  IWithTokenFactory &
  IWithStake &
  IWithStakes &
  IWithRollup &
  IWithRollupBlock &
  IWithEvidence &
  IWithLocked;
