import type { DuniterAdapter, MonetaryData } from './types';

const BMA_URL = 'https://g1.duniter.org';

async function bmaGet<T>(path: string): Promise<T> {
  const res = await fetch(`${BMA_URL}${path}`);
  if (!res.ok) throw new Error(`BMA ${path}: ${res.status}`);
  return res.json();
}

const joinBlockCache = new Map<string, number>();

export const v1Adapter: DuniterAdapter = {
  async fetchMonetary(): Promise<MonetaryData> {
    const [current, udBlocks] = await Promise.all([
      bmaGet<{
        monetaryMass: number;
        membersCount: number;
        number: number;
        medianTime: number;
      }>('/blockchain/current'),
      bmaGet<{ result: { blocks: number[] } }>('/blockchain/with/ud'),
    ]);

    const udBlockNumbers = udBlocks.result.blocks;
    const lastUdBlock = udBlockNumbers[udBlockNumbers.length - 1];
    const udBlock = await bmaGet<{ dividend: number }>(`/blockchain/block/${lastUdBlock}`);

    return {
      monetaryMass: String(current.monetaryMass),
      membersCount: current.membersCount,
      amount: String(udBlock.dividend),
      timestamp: new Date(current.medianTime * 1000).toISOString(),
      blockNumber: current.number,
      udBlockNumbers,
    };
  },

  async fetchMemberPubkeys(): Promise<string[]> {
    const data = await bmaGet<{ results: { pubkey: string }[] }>('/wot/members');
    return data.results.map((m) => m.pubkey);
  },

  async fetchMemberJoinBlocks(pubkeys: string[]): Promise<Map<string, number>> {
    const result = new Map<string, number>();
    const toFetch: string[] = [];

    for (const pk of pubkeys) {
      const cached = joinBlockCache.get(pk);
      if (cached !== undefined) {
        result.set(pk, cached);
      } else {
        toFetch.push(pk);
      }
    }

    const CONCURRENT = 10;
    for (let i = 0; i < toFetch.length; i += CONCURRENT) {
      const batch = toFetch.slice(i, i + CONCURRENT);
      await Promise.all(
        batch.map(async (pk) => {
          try {
            const data = await bmaGet<{
              results: { uids: { meta: { timestamp: string } }[] }[];
            }>(`/wot/lookup/${encodeURIComponent(pk)}`);
            const ts = data.results?.[0]?.uids?.[0]?.meta?.timestamp;
            if (ts) {
              const blockNum = parseInt(ts.split('-')[0], 10);
              if (!isNaN(blockNum)) {
                joinBlockCache.set(pk, blockNum);
                result.set(pk, blockNum);
              }
            }
          } catch {
            // Skip members we can't look up
          }
        })
      );
    }

    return result;
  },
};
