/**
 * Synor IBC SDK Types
 *
 * Inter-Blockchain Communication (IBC) protocol types for cross-chain interoperability.
 */

// ============================================================================
// Core Types
// ============================================================================

/** IBC Height representation */
export interface Height {
  /** Revision number (for hard forks) */
  revisionNumber: number;
  /** Block height */
  revisionHeight: number;
}

/** Timestamp in nanoseconds since Unix epoch */
export type Timestamp = bigint;

/** Chain identifier */
export interface ChainId {
  id: string;
}

/** Signer address */
export interface Signer {
  address: string;
}

/** IBC version with features */
export interface Version {
  identifier: string;
  features: string[];
}

/** Commitment prefix for Merkle paths */
export interface CommitmentPrefix {
  keyPrefix: Uint8Array;
}

// ============================================================================
// Client Types
// ============================================================================

/** Light client identifier */
export interface ClientId {
  id: string;
}

/** Light client types */
export type ClientType = 'tendermint' | 'solo-machine' | 'localhost' | 'wasm';

/** Light client state */
export interface ClientState {
  chainId: string;
  trustLevel: TrustLevel;
  trustingPeriod: bigint;
  unbondingPeriod: bigint;
  maxClockDrift: bigint;
  latestHeight: Height;
  frozenHeight?: Height;
  proofSpecs: ProofSpec[];
}

/** Trust level configuration */
export interface TrustLevel {
  numerator: number;
  denominator: number;
}

/** Proof specification */
export interface ProofSpec {
  leafSpec: LeafSpec;
  innerSpec: InnerSpec;
  maxDepth: number;
  minDepth: number;
}

export interface LeafSpec {
  hash: string;
  prehashKey: string;
  prehashValue: string;
  length: string;
  prefix: Uint8Array;
}

export interface InnerSpec {
  childOrder: number[];
  childSize: number;
  minPrefixLength: number;
  maxPrefixLength: number;
  emptyChild: Uint8Array;
  hash: string;
}

/** Consensus state at a specific height */
export interface ConsensusState {
  timestamp: Timestamp;
  root: Uint8Array;
  nextValidatorsHash: Uint8Array;
}

/** Block header */
export interface Header {
  signedHeader: SignedHeader;
  validatorSet: ValidatorSet;
  trustedHeight: Height;
  trustedValidators: ValidatorSet;
}

export interface SignedHeader {
  header: BlockHeader;
  commit: Commit;
}

export interface BlockHeader {
  version: { block: bigint; app: bigint };
  chainId: string;
  height: bigint;
  time: Timestamp;
  lastBlockId: BlockId;
  lastCommitHash: Uint8Array;
  dataHash: Uint8Array;
  validatorsHash: Uint8Array;
  nextValidatorsHash: Uint8Array;
  consensusHash: Uint8Array;
  appHash: Uint8Array;
  lastResultsHash: Uint8Array;
  evidenceHash: Uint8Array;
  proposerAddress: Uint8Array;
}

export interface BlockId {
  hash: Uint8Array;
  partSetHeader: { total: number; hash: Uint8Array };
}

export interface Commit {
  height: bigint;
  round: number;
  blockId: BlockId;
  signatures: CommitSig[];
}

export interface CommitSig {
  blockIdFlag: number;
  validatorAddress: Uint8Array;
  timestamp: Timestamp;
  signature: Uint8Array;
}

export interface ValidatorSet {
  validators: Validator[];
  proposer?: Validator;
  totalVotingPower: bigint;
}

export interface Validator {
  address: Uint8Array;
  pubKey: { type: string; value: Uint8Array };
  votingPower: bigint;
  proposerPriority: bigint;
}

// ============================================================================
// Connection Types
// ============================================================================

/** Connection identifier */
export interface ConnectionId {
  id: string;
}

/** Connection state */
export type ConnectionState = 'uninitialized' | 'init' | 'tryopen' | 'open';

/** Connection counterparty */
export interface ConnectionCounterparty {
  clientId: ClientId;
  connectionId?: ConnectionId;
  prefix: CommitmentPrefix;
}

/** Connection end */
export interface ConnectionEnd {
  clientId: ClientId;
  versions: Version[];
  state: ConnectionState;
  counterparty: ConnectionCounterparty;
  delayPeriod: bigint;
}

// ============================================================================
// Channel Types
// ============================================================================

/** Port identifier */
export interface PortId {
  id: string;
}

/** Channel identifier */
export interface ChannelId {
  id: string;
}

/** Channel ordering */
export type ChannelOrder = 'unordered' | 'ordered';

/** Channel state */
export type ChannelState = 'uninitialized' | 'init' | 'tryopen' | 'open' | 'closed';

/** Channel counterparty */
export interface ChannelCounterparty {
  portId: PortId;
  channelId?: ChannelId;
}

/** Channel end */
export interface Channel {
  state: ChannelState;
  ordering: ChannelOrder;
  counterparty: ChannelCounterparty;
  connectionHops: ConnectionId[];
  version: string;
}

/** Channel key (port, channel) */
export interface ChannelKey {
  portId: PortId;
  channelId: ChannelId;
}

// ============================================================================
// Packet Types
// ============================================================================

/** IBC Packet */
export interface Packet {
  /** Packet sequence number */
  sequence: bigint;
  /** Source port */
  sourcePort: PortId;
  /** Source channel */
  sourceChannel: ChannelId;
  /** Destination port */
  destPort: PortId;
  /** Destination channel */
  destChannel: ChannelId;
  /** Packet data (app-specific) */
  data: Uint8Array;
  /** Timeout height */
  timeoutHeight: Height;
  /** Timeout timestamp in nanoseconds */
  timeoutTimestamp: Timestamp;
}

/** Packet commitment hash */
export interface PacketCommitment {
  hash: Uint8Array;
}

/** Packet acknowledgement */
export type Acknowledgement =
  | { success: Uint8Array }
  | { error: string };

/** Timeout information */
export interface Timeout {
  height: Height;
  timestamp: Timestamp;
}

/** Packet receipt */
export interface PacketReceipt {
  receivedAt: Height;
  acknowledgement?: Acknowledgement;
}

/** Transfer packet data (ICS-20) */
export interface FungibleTokenPacketData {
  /** Token denomination */
  denom: string;
  /** Amount to transfer */
  amount: string;
  /** Sender address */
  sender: string;
  /** Receiver address */
  receiver: string;
  /** Optional memo */
  memo?: string;
}

// ============================================================================
// Swap Types (HTLC)
// ============================================================================

/** Swap identifier */
export interface SwapId {
  id: string;
}

/** Swap state */
export type SwapState = 'pending' | 'locked' | 'completed' | 'refunded' | 'expired' | 'cancelled';

/** Swap asset type */
export type SwapAsset =
  | { native: { amount: bigint } }
  | { ics20: { denom: string; amount: bigint } }
  | { ics721: { classId: string; tokenIds: string[] } };

/** Hashlock - hash of the secret */
export interface Hashlock {
  hash: Uint8Array;
}

/** Timelock - expiration time */
export interface Timelock {
  expiry: Timestamp;
}

/** Hashed Time-Locked Contract */
export interface Htlc {
  swapId: SwapId;
  state: SwapState;
  initiator: string;
  responder: string;
  asset: SwapAsset;
  hashlock: Hashlock;
  timelock: Timelock;
  secret?: Uint8Array;
  channelId?: ChannelId;
  portId?: PortId;
  createdAt: Timestamp;
  completedAt?: Timestamp;
}

/** Atomic swap between two chains */
export interface AtomicSwap {
  swapId: SwapId;
  initiatorHtlc: Htlc;
  responderHtlc?: Htlc;
  state: SwapState;
}

/** Swap packet actions */
export type SwapAction = 'initiate' | 'respond' | 'claim' | 'refund';

/** Swap packet data */
export interface SwapPacketData {
  swapId: SwapId;
  action: SwapAction;
  initiator: string;
  responder: string;
  asset: SwapAsset;
  hashlock: Hashlock;
  timelockExpiry: bigint;
  secret?: Uint8Array;
}

// ============================================================================
// Proof Types
// ============================================================================

/** Merkle proof */
export interface MerkleProof {
  proofs: ProofOp[];
}

export interface ProofOp {
  type: 'iavl' | 'simple' | 'ics23';
  key: Uint8Array;
  data: Uint8Array;
}

/** Commitment proof */
export interface CommitmentProof {
  proof: MerkleProof;
  height: Height;
}

// ============================================================================
// Event Types
// ============================================================================

/** IBC events */
export type IbcEvent =
  | { type: 'createClient'; clientId: ClientId; clientType: ClientType; consensusHeight: Height }
  | { type: 'updateClient'; clientId: ClientId; consensusHeight: Height }
  | { type: 'openInitConnection'; connectionId: ConnectionId; clientId: ClientId; counterpartyClientId: ClientId }
  | { type: 'openTryConnection'; connectionId: ConnectionId; clientId: ClientId; counterpartyConnectionId: ConnectionId }
  | { type: 'openAckConnection'; connectionId: ConnectionId }
  | { type: 'openConfirmConnection'; connectionId: ConnectionId }
  | { type: 'openInitChannel'; portId: PortId; channelId: ChannelId; connectionId: ConnectionId }
  | { type: 'openTryChannel'; portId: PortId; channelId: ChannelId; counterpartyChannelId: ChannelId }
  | { type: 'openAckChannel'; portId: PortId; channelId: ChannelId }
  | { type: 'openConfirmChannel'; portId: PortId; channelId: ChannelId }
  | { type: 'closeChannel'; portId: PortId; channelId: ChannelId }
  | { type: 'sendPacket'; packet: Packet }
  | { type: 'receivePacket'; packet: Packet }
  | { type: 'acknowledgePacket'; packet: Packet; acknowledgement: Acknowledgement }
  | { type: 'timeoutPacket'; packet: Packet }
  | { type: 'swapInitiated'; swapId: SwapId; initiator: string; responder: string }
  | { type: 'swapCompleted'; swapId: SwapId }
  | { type: 'swapRefunded'; swapId: SwapId };

// ============================================================================
// Request/Response Types
// ============================================================================

/** Create client parameters */
export interface CreateClientParams {
  clientType: ClientType;
  clientState: ClientState;
  consensusState: ConsensusState;
}

/** Update client parameters */
export interface UpdateClientParams {
  clientId: ClientId;
  header: Header;
}

/** Connection open init parameters */
export interface ConnOpenInitParams {
  clientId: ClientId;
  counterpartyClientId: ClientId;
  counterpartyPrefix?: CommitmentPrefix;
  version?: Version;
  delayPeriod?: bigint;
}

/** Connection open try parameters */
export interface ConnOpenTryParams {
  clientId: ClientId;
  counterpartyClientId: ClientId;
  counterpartyConnectionId: ConnectionId;
  counterpartyPrefix: CommitmentPrefix;
  counterpartyVersions: Version[];
  proofInit: Uint8Array;
  proofHeight: Height;
  proofConsensus: Uint8Array;
  consensusHeight: Height;
}

/** Channel open init parameters */
export interface ChanOpenInitParams {
  portId: PortId;
  ordering: ChannelOrder;
  connectionId: ConnectionId;
  counterpartyPort: PortId;
  version: string;
}

/** Channel open try parameters */
export interface ChanOpenTryParams {
  portId: PortId;
  ordering: ChannelOrder;
  connectionId: ConnectionId;
  counterpartyPort: PortId;
  counterpartyChannel: ChannelId;
  version: string;
  counterpartyVersion: string;
  proofInit: Uint8Array;
  proofHeight: Height;
}

/** Send packet parameters */
export interface SendPacketParams {
  sourcePort: PortId;
  sourceChannel: ChannelId;
  data: Uint8Array;
  timeoutHeight?: Height;
  timeoutTimestamp?: Timestamp;
}

/** Transfer parameters (ICS-20) */
export interface TransferParams {
  sourcePort: PortId;
  sourceChannel: ChannelId;
  token: { denom: string; amount: string };
  sender: string;
  receiver: string;
  timeoutHeight?: Height;
  timeoutTimestamp?: Timestamp;
  memo?: string;
}

/** Initiate swap parameters */
export interface InitiateSwapParams {
  responder: string;
  initiatorAsset: SwapAsset;
  responderAsset: SwapAsset;
  channelId?: ChannelId;
  portId?: PortId;
}

/** Respond to swap parameters */
export interface RespondSwapParams {
  swapId: SwapId;
  asset: SwapAsset;
}

/** Claim swap parameters */
export interface ClaimSwapParams {
  swapId: SwapId;
  secret: Uint8Array;
}

// ============================================================================
// Configuration
// ============================================================================

/** IBC SDK configuration */
export interface IbcConfig {
  /** API key for authentication */
  apiKey: string;
  /** API endpoint URL */
  endpoint?: string;
  /** WebSocket endpoint URL */
  wsEndpoint?: string;
  /** Request timeout in milliseconds */
  timeout?: number;
  /** Number of retries */
  retries?: number;
  /** Chain ID */
  chainId?: string;
  /** Enable debug logging */
  debug?: boolean;
}

/** IBC error codes */
export type IbcErrorCode =
  | 'CLIENT_CLOSED'
  | 'CLIENT_NOT_FOUND'
  | 'CONNECTION_NOT_FOUND'
  | 'CHANNEL_NOT_FOUND'
  | 'PORT_NOT_BOUND'
  | 'PACKET_NOT_FOUND'
  | 'SWAP_NOT_FOUND'
  | 'INVALID_PROOF'
  | 'TIMEOUT_EXPIRED'
  | 'INVALID_SECRET'
  | 'NETWORK_ERROR'
  | 'HTTP_ERROR';

/** IBC exception */
export class IbcException extends Error {
  constructor(
    message: string,
    public code?: IbcErrorCode,
    public status?: number
  ) {
    super(message);
    this.name = 'IbcException';
  }
}
