import { write } from "bun";

const API_BASE = "https://eldenring.fanapis.com/api";

async function fetchAll(endpoint: string) {
  let allData: any[] = [];
  let page = 0;
  const limit = 100;
  
  while (true) {
    const res = await fetch(`${API_BASE}/${endpoint}?limit=${limit}&page=${page}`);
    if (!res.ok) {
      console.error(`Error fetching ${endpoint}:`, res.status);
      break;
    }
    const data = await res.json();
    if (!data.data || data.data.length === 0) {
      break;
    }
    allData = allData.concat(data.data);
    console.log(`Fetched ${allData.length} ${endpoint}...`);
    if (data.data.length < limit) {
      break;
    }
    page++;
  }
  return allData;
}

function extractRegion(entityRegion: string | null | undefined, locationStr: string | null | undefined, locationLookup: Map<string, string>, uniqueRegions: Set<string>): string | null {
  // 1. If the entity has a region, use it (and clean up typos from API)
  if (entityRegion) {
    let r = entityRegion;
    if (r === "Liunia of the Lakes") r = "Liurnia of the Lakes";
    if (r === "Mountaintop of the Giants") r = "Mountaintops of the Giants";
    if (r === "Altus Pleateau") r = "Altus Plateau";
    uniqueRegions.add(r);
    return r;
  }
  
  // 2. Lookup via locations map
  if (locationStr) {
    for (const [locName, regionName] of locationLookup.entries()) {
      if (locationStr.toLowerCase().includes(locName.toLowerCase())) {
        return regionName;
      }
    }
    
    // 3. Fallback: check if the location string itself contains a known dynamic region
    for (const region of uniqueRegions) {
      if (locationStr.toLowerCase().includes(region.toLowerCase())) {
        return region;
      }
    }
  }

  return null;
}

async function main() {
  console.log("Fetching locations...");
  const locations = await fetchAll("locations");
  const uniqueRegions = new Set<string>();
  const locationLookup = new Map<string, string>();
  
  // Normalize regions and build a lookup map: LocationName -> Region
  for (const loc of locations) {
    if (loc.region) {
      let r = loc.region;
      if (r === "Liunia of the Lakes" || r === "Liurnia") r = "Liurnia of the Lakes";
      if (r === "Mountaintop of the Giants") r = "Mountaintops of the Giants";
      if (r === "Altus Pleateau") r = "Altus Plateau";
      uniqueRegions.add(r);
      locationLookup.set(loc.name, r);
    }
  }

  console.log("Fetching bosses...");
  const bosses = await fetchAll("bosses");
  
  console.log("Fetching creatures...");
  const creatures = await fetchAll("creatures");
  
  console.log("Fetching npcs...");
  const npcs = await fetchAll("npcs");

  const livingEntities = [
    ...bosses.map(b => ({ ...b, _type: "boss" })),
    ...creatures.map(c => ({ ...c, _type: "creature" })),
    ...npcs.map(n => ({ ...n, _type: "npc" }))
  ];

  const cleanedEntities = livingEntities.map(entity => {
    // combine all possible location info
    const cleanRegion = extractRegion(entity.region, entity.location, locationLookup, uniqueRegions);
    
    return {
      id: entity.id,
      name: entity.name,
      type: entity._type,
      cleanRegion: cleanRegion || "Unknown",
      originalLocation: entity.location,
      drops: entity.drops || []
    };
  });
  
  // Save regions based on what was dynamically found in the API
  const regionsData = Array.from(uniqueRegions).map((r, i) => ({ id: i + 1, name: r }));

  console.log("Fetching items...");
  const items = await fetchAll("items");
  // you might also want weapons, armors etc depending on what "items" means to the user.
  // The fan API separates items, weapons, armors, etc. Let's just fetch items for now.

  const output = {
    regions: regionsData,
    entities: cleanedEntities,
    items: items.map(i => ({ id: i.id, name: i.name, type: i.type, effect: i.effect }))
  };

  await write("./db/fanapi_data.json", JSON.stringify(output, null, 2));
  console.log("Saved to db/fanapi_data.json");
}

main().catch(console.error);
