import { DatabaseSync } from "node:sqlite";
import { Nat, Point } from "./types.ts";

export function db_setup(db: DatabaseSync) {
  // enable WAL for performance
  db.exec("PRAGMA journal_mode=WAL;");

  db.exec(`
        create table stops (
            href text,
            lat real,
            lon real
        ) strict;
  `);
  // system and hub are both "OCCT" | "BCT"
  db.exec(`
        create table systems (
            href text,
            system text
        ) strict;
  `);
  insert_stops(db);
  db.exec(`
        create table hub_stops(
            href text,
            hub text
        ) strict;
  `);

  // Greyhound station for broome county
  insert_hubs(db, "BCT", { lat: 42.10153070333811, lon: -75.91019831469858 }, {
    discrim: "count",
    count: 13,
  });
}

function insert_hubs(
  db: DatabaseSync,
  hub: "OCCT" | "BCT",
  hub_location: Point,
  options: { discrim: "distance"; distance: number } | {
    discrim: "count";
    count: Nat;
  },
) {
  if (options.discrim != "count") {
    throw Error("feck");
  }
  db.exec(
    `insert into hub_stops (href, hub) values ${
      select_closest(db, hub_location, options.count).map((href) => {
        return `("${href}", "${hub}")`;
      }).join(",")
    }`,
  );
}

// taken from chatGPT originally https://chatgpt.com/share/67e174e7-f5a4-8002-a502-5a16f00f0602
function insert_stops(db: DatabaseSync) {
  const stopsDir = "./stops";

  for (const entry of Deno.readDirSync(stopsDir)) {
    if (entry.isFile) {
      const filePath = `${stopsDir}/${entry.name}`;
      const content = Deno.readTextFileSync(filePath);
      let data;
      try {
        data = JSON.parse(content);
      } catch (error) {
        console.error(`Skipping file ${entry.name} - not valid JSON.`);
        continue;
      }

      const href = entry.name;
      const lat = data.lattitude;
      const lon = data.longitude;
      const system = href.split("_")[0];

      if (system == "OCCT") continue;

      // TODO: batch DB
      // Note: this is fine all the data is from a place we control, no user input
      db.exec(
        `INSERT INTO stops (href, lat, lon) VALUES ('${href}', ${lat}, ${lon});`,
      );

      db.exec(
        `INSERT INTO systems (href, system) VALUES ('${href}', '${system}');`,
      );
    }
  }
}

export function select_closest(
  db: DatabaseSync,
  point: Point,
  limit: Nat,
) {
  try {
    // manhattan distance due to sqlite not being built with math functions
    const prepped = db.prepare(`
        select href from (
            select 
                href,
                abs(lat-$lat)+abs(lon-$lon) as dist
            from stops order by dist limit $count);
    `);
    return prepped.all({
      count: limit,
      lat: point.lat,
      lon: point.lon,
    }).map((o) => (o as { href: string }).href);
  } catch (e) {
    console.log(e);
    throw e;
  }
}
