import type BN from "../crypto/bn.extension";
import type Point from "../crypto/point";
import type { Network } from "../core/network/network";
import type { ITransaction } from "../core/transaction/interfaces";

export interface BufferParams {
  buf?: Uint8Array;
  pos?: number;
}

export interface BufferWriterOptions {
  bufs?: Uint8Array[];
}

export interface NetworkParams {
  name: string;
  alias: string;
  prefix: string;
  pubkeyhash: number;
  privatekey: number;
  scripthash: number;
  xpubkey: number;
  xprivkey: number;
  networkMagic: number;
  port: number;
  dnsSeeds: string[];
}

export interface BNOptions {
  endian?: "little" | "big";
  size?: number;
  bignum?: boolean;
}

export interface GroupIdData {
  hashBuffer: Uint8Array;
  nonce: bigint;
}

export interface ISignature {
  r: BN;
  s: BN;
  i?: number; //public key recovery parameter in range [0, 3]
  compressed?: boolean; // whether the recovered pubkey is compressed
  toBuffer(isSchnorr: boolean): Uint8Array
}

export interface IDigitalSignature {
  hashbuf: Uint8Array;
  endian?: "big" | "little";
  privkey: IPrivateKey;
  pubkey: IPublicKey;
  sig?: ISignature;
  verified?: boolean;
  sign(): this;
  verify(): this;
}

export interface IPrivateKey {
  compressed: boolean;
  network: Network;
  bn: BN;
  get publicKey(): IPublicKey;
  toString(): string;
  toWIF(): string;
  toBigNumber(): BN;
  toBuffer(): Uint8Array;
  toBufferNoPadding(): Uint8Array;
  toPublicKey(): IPublicKey;
  toJSON(): PrivateKeyDto;
  toObject(): PrivateKeyDto;
  inspect(): string;
}

export interface IPublicKey {
  point: Point;
  compressed?: boolean;
  network?: Network;
  toString(): string;
  toJSON(): PublicKeyDto;
  toObject(): PublicKeyDto;
  toDER(): Uint8Array;
  toBuffer(): Uint8Array;
  inspect(): string;
}

export interface PrivateKeyDto {
  compressed: boolean;
  network: string;
  bn: string;
}

export interface PublicKeyDto {
  x: string;
  y: string;
  compressed: boolean;
  network: string;
}

interface IHDKey {
  network: Network;
  depth: number;
  parentFingerPrint: Uint8Array;
  fingerPrint: Uint8Array;
  chainCode: Uint8Array;
  childIndex: number;
  checksum: Uint8Array;
}

export interface IHDPrivateKey extends IHDKey {
  privateKey: IPrivateKey;
  publicKey?: IPublicKey;
  xprivkey: string;
}

export interface IHDPublicKey extends IHDKey {
  publicKey: IPublicKey;
  xpubkey: string;
}

interface HDKeyBuffers {
  version: Uint8Array;
  depth: Uint8Array;
  parentFingerPrint: Uint8Array;
  childIndex: Uint8Array;
  chainCode: Uint8Array;
  checksum?: Uint8Array;
}

export interface HDPublicKeyBuffers extends  HDKeyBuffers {
  publicKey: Uint8Array;
}

export interface HDPrivateKeyBuffers extends  HDKeyBuffers {
  privateKey: Uint8Array;
}

interface HDKeyDto {
  network: string;
  depth: number;
  fingerPrint: number;
  parentFingerPrint: number;
  childIndex: number;
  chainCode: string;
  checksum: number;
}

export interface HDPrivateKeyDto extends HDKeyDto {
  privateKey: string;
  xprivkey: string;
}

export interface HDPublicKeyDto extends HDKeyDto {
  publicKey: string;
  xpubkey: string;
}

export type HDPrivateKeyMinimalDto = Omit<HDPrivateKeyDto, 'xprivkey' | 'checksum' | 'fingerPrint'>;
export type HDPublicKeyMinimalDto = Omit<HDPublicKeyDto, 'xpubkey' | 'checksum' | 'fingerPrint'>;

export interface ScriptChunk {
  buf?: Uint8Array;
  len?: number;
  opcodenum: number;
}

export interface IScript {
  chunks: ScriptChunk[];
}

export interface AddressDto {
  data: string;
  network: string;
  type: string;
}

export interface IMessage {
  message: string;
}

export interface IBlockHeader {
  hash?: string;
  prevHash: string | Uint8Array;
  bits: number;
  ancestorHash: string | Uint8Array;
  merkleRoot: string | Uint8Array;
  txFilter: string | Uint8Array;
  time: number;
  height: number;
  chainWork: string | Uint8Array;
  size: number;
  txCount: number;
  poolFee: number;
  utxoCommitment: string | Uint8Array;
  minerData: string | Uint8Array;
  nonce: string | Uint8Array;
}

export interface IBlock {
  header: IBlockHeader;
  transactions: ITransaction[];
}
