import { ethers } from 'ethers';

export type CheckpointHeaderStruct = {
  batchId: bigint;
  previousBatchId: bigint;
  chainId: bigint;
  checkpointBlock: bigint;
  startBlock: bigint;
  endBlock: bigint;
  blockHash: string;
  stateRoot: string;
  paymentsRoot: string;
  receiptsRoot: string;
  txCount: number;
  flags: number;
  submittedAt: bigint;
  submitter: string;
  contentURI: string;
};

const BATCH_ATTESTATION_TYPES: Record<string, ethers.TypedDataField[]> = {
  BatchAttestation: [
    { name: 'chainId', type: 'uint64' },
    { name: 'batchId', type: 'uint64' },
    { name: 'checkpointBlock', type: 'uint256' },
    { name: 'blockHash', type: 'bytes32' },
    { name: 'stateRoot', type: 'bytes32' },
    { name: 'paymentsRoot', type: 'bytes32' },
    { name: 'previousBatchId', type: 'uint64' },
  ],
};

/** Matches CheckpointEIP712.digest / ValidatorSigVerifierExtension.beforeSubmit. */
export async function signBatchAttestation(
  wallet: ethers.Wallet,
  verifyingContract: string,
  header: CheckpointHeaderStruct
): Promise<string> {
  const chainId = Number((await wallet.provider!.getNetwork()).chainId);
  const domain = {
    name: 'Chain138MainnetCheckpoint',
    version: '2',
    chainId,
    verifyingContract,
  };
  const message = {
    chainId: header.chainId,
    batchId: header.batchId,
    checkpointBlock: header.checkpointBlock,
    blockHash: header.blockHash,
    stateRoot: header.stateRoot,
    paymentsRoot: header.paymentsRoot,
    previousBatchId: header.previousBatchId,
  };
  const sig = await wallet.signTypedData(domain, BATCH_ATTESTATION_TYPES, message);
  return normalizeEcdsaSignature(sig);
}

/** OpenZeppelin ECDSA.recover expects v=27|28; ethers v6 may return 0|1. */
export function normalizeEcdsaSignature(sig: string): string {
  const bytes = ethers.getBytes(sig);
  if (bytes.length !== 65) return sig;
  const v = bytes[64];
  if (v < 27) bytes[64] = v + 27;
  return ethers.hexlify(bytes);
}
