import { Contract, JsonRpcProvider, type InterfaceAbi } from 'ethers';
import { logger } from '../utils/logger';
import { emitOmnlWebhook } from '../services/omnl-webhooks';
import { loadLastProcessedBlock, saveLastProcessedBlock } from './omnl-poller-state';
import { omnlReserveStore138 } from '../services/omnl-chain138-addresses';

const RESERVE_ABI: InterfaceAbi = [
  'event ReserveCommitted(bytes32 indexed lineId,uint256 R,uint256 validUntil,bytes32 evidenceHash,bytes32 merkleRoot,uint256 version,address indexed by)',
];

/**
 * Polls ReserveCommitted on Chain 138 / 651940 for ops visibility.
 * Persists last processed block per chain (`OMNL_POLLER_STATE_PATH` or `.omnl-poller-state.json`).
 */
export class OmnlEventPoller {
  private timers: NodeJS.Timeout[] = [];

  start(): void {
    const interval = parseInt(process.env.OMNL_EVENT_POLL_INTERVAL_MS || '60000', 10);
    const chains = (process.env.OMNL_EVENT_POLL_CHAINS || '138,651940').split(',').map((s) => parseInt(s.trim(), 10));

    for (const chainId of chains) {
      const addr =
        chainId === 138
          ? omnlReserveStore138()
          : chainId === 651940
            ? process.env.OMNL_RESERVE_STORE_651940
            : process.env[`OMNL_RESERVE_STORE_${chainId}`];
      const rpc =
        chainId === 138
          ? process.env.RPC_URL_138 || process.env.RPC_URL
          : process.env.CHAIN_651940_RPC_URL || 'https://mainnet-rpc.alltra.global';
      if (!addr || !rpc) {
        logger.warn(`OMNL event poll skipped chain ${chainId}: missing store or RPC`);
        continue;
      }

      const persisted = loadLastProcessedBlock(chainId);
      let lastBlock = persisted ?? 0;

      const provider = new JsonRpcProvider(rpc, chainId);
      const c = new Contract(addr, RESERVE_ABI, provider);

      const tick = async () => {
        try {
          const head = await provider.getBlockNumber();
          const from = lastBlock === 0 ? Math.max(0, head - 99) : lastBlock + 1;
          if (from > head) return;
          const evs = await c.queryFilter('ReserveCommitted', from, head);
          for (const ev of evs) {
            const deliveryId = `${chainId}-${ev.blockNumber}-${ev.index}`;
            logger.info('OMNL ReserveCommitted', { chainId, logIndex: ev.index, deliveryId });
            const args = (ev as { args?: { lineId?: string; version?: bigint; R?: bigint } }).args;
            void emitOmnlWebhook({
              event: 'ReserveCommitted',
              chainId,
              lineId: args?.lineId,
              deliveryId,
              payload: {
                blockNumber: ev.blockNumber,
                transactionHash: ev.transactionHash,
                version: args?.version?.toString(),
                r: args?.R?.toString(),
              },
              ts: new Date().toISOString(),
            });
          }
          lastBlock = head;
          saveLastProcessedBlock(chainId, head);
        } catch (e) {
          logger.error(`OMNL poll error chain ${chainId}`, e);
        }
      };

      void tick();
      const t = setInterval(() => void tick(), interval);
      this.timers.push(t);
    }
  }

  stop(): void {
    for (const t of this.timers) {
      clearInterval(t);
    }
    this.timers = [];
  }
}
