/**
 * LiquidityManager recenter helper and Anvil block-mining utility.
 *
 * Pure Node.js — no browser/Playwright dependency.
 */
import { Interface, JsonRpcProvider, Wallet } from 'ethers';
import { rpcCall } from './rpc.js';
import { waitForReceipt } from './swap.js';

const RECENTER_ABI = [
  'function recenter() external returns (bool isUp)',
  'event Recentered(int24 indexed currentTick, bool indexed isUp)',
];

export interface RecenterConfig {
  rpcUrl: string;
  /** Address of the LiquidityManager contract */
  lmAddress: string;
  /**
   * Private key of an account with recenter access.
   * In the local Anvil stack, recenterAccess is granted to the deployer
   * (Anvil account index 0) and the txnBot (Anvil account index 2).
   * See scripts/bootstrap-common.sh for how access is granted at deploy time.
   */
  privateKey: string;
  /** Address corresponding to privateKey */
  accountAddress: string;
}

/**
 * Call LiquidityManager.recenter() from an authorized account.
 *
 * Reads isUp from the Recentered(int24 currentTick, bool isUp) event emitted
 * by the mined transaction — not from a follow-up eth_call, which would
 * simulate a second recenter on already-updated state and return the wrong value.
 *
 * @returns isUp - true if price moved up
 */
export async function triggerRecenter(config: RecenterConfig): Promise<boolean> {
  const provider = new JsonRpcProvider(config.rpcUrl);
  const wallet = new Wallet(config.privateKey, provider);

  const iface = new Interface(RECENTER_ABI);
  const data = iface.encodeFunctionData('recenter', []);

  console.log('[recenter] Calling LiquidityManager.recenter()...');
  const tx = await wallet.sendTransaction({ to: config.lmAddress, data });
  await waitForReceipt(config.rpcUrl, tx.hash);
  console.log(`[recenter] recenter() mined: ${tx.hash}`);

  provider.destroy();

  // Parse isUp from the Recentered event in the receipt logs.
  // A follow-up eth_call would simulate on post-recenter state and give the wrong result.
  const receipt = (await rpcCall(config.rpcUrl, 'eth_getTransactionReceipt', [tx.hash])) as {
    logs: Array<{ address: string; topics: string[]; data: string }>;
  };

  const recenterEventTopic = iface.getEvent('Recentered')!.topicHash;
  const log = receipt.logs.find(
    l =>
      l.address.toLowerCase() === config.lmAddress.toLowerCase() &&
      l.topics[0] === recenterEventTopic,
  );
  if (!log) {
    throw new Error('[recenter] Recentered event not found in receipt — did the tx revert silently?');
  }

  const parsed = iface.parseLog({ topics: log.topics, data: log.data });
  const isUp = Boolean(parsed!.args.isUp);
  console.log(`[recenter] isUp = ${isUp}`);

  return isUp;
}

/**
 * Mine `blocks` empty blocks on Anvil to advance time.
 * Useful to get past MIN_RECENTER_INTERVAL (if set).
 *
 * Uses the anvil_mine RPC method.
 */
export async function mineBlocks(rpcUrl: string, blocks: number): Promise<void> {
  if (blocks <= 0) throw new Error(`mineBlocks: blocks must be > 0, got ${blocks}`);
  await rpcCall(rpcUrl, 'anvil_mine', ['0x' + blocks.toString(16)]);
  console.log(`[recenter] Mined ${blocks} blocks`);
}
