#!/usr/bin/env node

import { loadEnvFile, CHROME_UA, runSeed } from './_seed-utils.mjs';

loadEnvFile(import.meta.url);

const CANONICAL_KEY_PREFIX = 'displacement:summary:v1';
const CACHE_TTL = 86400; // 24 hours — UNHCR data is annual
export const MIN_DISPLACEMENT_COUNTRIES = 100;

const COUNTRY_CENTROIDS = {
  AFG: [33.9, 67.7], SYR: [35.0, 38.0], UKR: [48.4, 31.2], SDN: [15.5, 32.5],
  SSD: [6.9, 31.3], SOM: [5.2, 46.2], COD: [-4.0, 21.8], MMR: [19.8, 96.7],
  YEM: [15.6, 48.5], ETH: [9.1, 40.5], VEN: [6.4, -66.6], IRQ: [33.2, 43.7],
  COL: [4.6, -74.1], NGA: [9.1, 7.5], PSE: [31.9, 35.2], TUR: [39.9, 32.9],
  DEU: [51.2, 10.4], PAK: [30.4, 69.3], UGA: [1.4, 32.3], BGD: [23.7, 90.4],
  KEN: [0.0, 38.0], TCD: [15.5, 19.0], JOR: [31.0, 36.0], LBN: [33.9, 35.5],
  EGY: [26.8, 30.8], IRN: [32.4, 53.7], TZA: [-6.4, 34.9], RWA: [-1.9, 29.9],
  CMR: [7.4, 12.4], MLI: [17.6, -4.0], BFA: [12.3, -1.6], NER: [17.6, 8.1],
  CAF: [6.6, 20.9], MOZ: [-18.7, 35.5], USA: [37.1, -95.7], FRA: [46.2, 2.2],
  GBR: [55.4, -3.4], IND: [20.6, 79.0], CHN: [35.9, 104.2], RUS: [61.5, 105.3],
};

function getCoordinates(code) {
  const centroid = COUNTRY_CENTROIDS[code];
  if (!centroid) return undefined;
  return { latitude: centroid[0], longitude: centroid[1] };
}

async function fetchUnhcrYearItems(year) {
  const limit = 10000;
  const maxPageGuard = 25;
  const items = [];

  for (let page = 1; page <= maxPageGuard; page++) {
    const resp = await fetch(
      `https://api.unhcr.org/population/v1/population/?year=${year}&limit=${limit}&page=${page}&coo_all=true&coa_all=true`,
      {
        headers: {
          Accept: 'application/json',
          'User-Agent': CHROME_UA,
        },
        signal: AbortSignal.timeout(15_000),
      },
    );

    if (!resp.ok) return null;

    const data = await resp.json();
    const pageItems = Array.isArray(data.items) ? data.items : [];
    if (pageItems.length === 0) break;
    items.push(...pageItems);

    const maxPages = Number(data.maxPages);
    if (Number.isFinite(maxPages) && maxPages > 0) {
      if (page >= maxPages) break;
      continue;
    }

    if (pageItems.length < limit) break;
  }

  return items;
}

async function fetchDisplacementSummary() {
  const currentYear = new Date().getFullYear();
  let rawItems = [];
  let dataYearUsed = currentYear;

  for (let y = currentYear; y >= currentYear - 2; y--) {
    const items = await fetchUnhcrYearItems(y);
    if (!items) continue;
    if (items.length > 0) {
      rawItems = items;
      dataYearUsed = y;
      break;
    }
  }

  if (rawItems.length === 0) throw new Error('No UNHCR data available for current or past 2 years');

  const byOrigin = {};
  const byAsylum = {};
  const flowMap = {};
  let totalRefugees = 0;
  let totalAsylumSeekers = 0;
  let totalIdps = 0;
  let totalStateless = 0;

  for (const item of rawItems) {
    const originCode = item.coo_iso || '';
    const asylumCode = item.coa_iso || '';
    const refugees = Number(item.refugees) || 0;
    const asylumSeekers = Number(item.asylum_seekers) || 0;
    const idps = Number(item.idps) || 0;
    const stateless = Number(item.stateless) || 0;

    totalRefugees += refugees;
    totalAsylumSeekers += asylumSeekers;
    totalIdps += idps;
    totalStateless += stateless;

    if (originCode) {
      if (!byOrigin[originCode]) {
        byOrigin[originCode] = { name: item.coo_name || originCode, refugees: 0, asylumSeekers: 0, idps: 0, stateless: 0 };
      }
      byOrigin[originCode].refugees += refugees;
      byOrigin[originCode].asylumSeekers += asylumSeekers;
      byOrigin[originCode].idps += idps;
      byOrigin[originCode].stateless += stateless;
    }

    if (asylumCode) {
      if (!byAsylum[asylumCode]) {
        byAsylum[asylumCode] = { name: item.coa_name || asylumCode, refugees: 0, asylumSeekers: 0 };
      }
      byAsylum[asylumCode].refugees += refugees;
      byAsylum[asylumCode].asylumSeekers += asylumSeekers;
    }

    if (originCode && asylumCode && refugees > 0) {
      const flowKey = `${originCode}->${asylumCode}`;
      if (!flowMap[flowKey]) {
        flowMap[flowKey] = { originCode, originName: item.coo_name || originCode, asylumCode, asylumName: item.coa_name || asylumCode, refugees: 0 };
      }
      flowMap[flowKey].refugees += refugees;
    }
  }

  const countries = {};

  for (const [code, data] of Object.entries(byOrigin)) {
    countries[code] = {
      code,
      name: data.name,
      refugees: data.refugees,
      asylumSeekers: data.asylumSeekers,
      idps: data.idps,
      stateless: data.stateless,
      totalDisplaced: data.refugees + data.asylumSeekers + data.idps + data.stateless,
      hostRefugees: 0,
      hostAsylumSeekers: 0,
      hostTotal: 0,
    };
  }

  for (const [code, data] of Object.entries(byAsylum)) {
    const hostRefugees = data.refugees;
    const hostAsylumSeekers = data.asylumSeekers;
    const hostTotal = hostRefugees + hostAsylumSeekers;

    if (!countries[code]) {
      countries[code] = {
        code,
        name: data.name,
        refugees: 0,
        asylumSeekers: 0,
        idps: 0,
        stateless: 0,
        totalDisplaced: 0,
        hostRefugees,
        hostAsylumSeekers,
        hostTotal,
      };
    } else {
      countries[code].hostRefugees = hostRefugees;
      countries[code].hostAsylumSeekers = hostAsylumSeekers;
      countries[code].hostTotal = hostTotal;
    }
  }

  const sortedCountries = Object.values(countries)
    .sort((a, b) => Math.max(b.totalDisplaced, b.hostTotal) - Math.max(a.totalDisplaced, a.hostTotal))
    .map((d) => ({
      code: d.code,
      name: d.name,
      refugees: d.refugees,
      asylumSeekers: d.asylumSeekers,
      idps: d.idps,
      stateless: d.stateless,
      totalDisplaced: d.totalDisplaced,
      hostRefugees: d.hostRefugees,
      hostAsylumSeekers: d.hostAsylumSeekers,
      hostTotal: d.hostTotal,
      location: getCoordinates(d.code),
    }));

  const topFlows = Object.values(flowMap)
    .sort((a, b) => b.refugees - a.refugees)
    .map((f) => ({
      originCode: f.originCode,
      originName: f.originName,
      asylumCode: f.asylumCode,
      asylumName: f.asylumName,
      refugees: f.refugees,
      originLocation: getCoordinates(f.originCode),
      asylumLocation: getCoordinates(f.asylumCode),
    }));

  return {
    summary: {
      year: dataYearUsed,
      globalTotals: {
        refugees: totalRefugees,
        asylumSeekers: totalAsylumSeekers,
        idps: totalIdps,
        stateless: totalStateless,
        total: totalRefugees + totalAsylumSeekers + totalIdps + totalStateless,
      },
      countries: sortedCountries,
      topFlows,
    },
  };
}

export function validate(data) {
  return Boolean(
    data?.summary &&
    typeof data.summary.year === 'number' &&
    Array.isArray(data.summary.countries) &&
    data.summary.countries.length >= MIN_DISPLACEMENT_COUNTRIES
  );
}

const currentYear = new Date().getFullYear();
const canonicalKey = `${CANONICAL_KEY_PREFIX}:${currentYear}`;

export function declareRecords(data) {
  return data?.summary?.countries?.length ?? 0;
}

export const seedOptions = {
  validateFn: validate,
  ttlSeconds: CACHE_TTL,
  sourceVersion: `unhcr-${currentYear}`,
  declareRecords,
  schemaVersion: 1,
  maxStaleMin: 3600,
  emptyDataIsFailure: true,
};

if (process.argv[1]?.endsWith('seed-displacement-summary.mjs')) {
  runSeed('displacement', 'summary', canonicalKey, fetchDisplacementSummary, seedOptions).catch((err) => {
    const _cause = err.cause ? ` (cause: ${err.cause.message || err.cause.code || err.cause})` : ''; console.error('FATAL:', (err.message || err) + _cause);
    process.exit(1);
  });
}
