// title:  game title
// author: game developer
// desc:   short description
// script: js

/// <reference path="./input.ts"/>

// Maps are [dest source range]
const input = exampleInput;

let seeds = input[0].split(" ").map((o) => Number(o));
seeds.shift();
const seedsPairs: [number, number][] = [];
for (let i = 0; i < seeds.length; i += 2) {
  seedsPairs.push([seeds[i], seeds[i + 1]]);
}
trace(JSON.stringify(seedsPairs));

let seedToSoil: number[][] = [];
let soilToFertilizer: number[][] = [];
let fertilizerToWater: number[][] = [];
let waterToLight: number[][] = [];
let lightToTemp: number[][] = [];
let tempToHumidity: number[][] = [];
let humidityToLocation: number[][] = [];

let curr = seedToSoil;

// Roughly save input values
for (const line of input) {
  if (line === "seed-to-soil map:") {
    curr = seedToSoil;
  }
  if (line === "soil-to-fertilizer map:") {
    curr = soilToFertilizer;
  }
  if (line === "fertilizer-to-water map:") {
    curr = fertilizerToWater;
  }
  if (line === "water-to-light map:") {
    curr = waterToLight;
  }
  if (line === "light-to-temperature map:") {
    curr = lightToTemp;
  }
  if (line === "temperature-to-humidity map:") {
    curr = tempToHumidity;
  }
  if (line === "humidity-to-location map:") {
    curr = humidityToLocation;
  }
  curr.push(line.split(" ").map((o) => Number(o)));
}

// Clean and sort the maps

for (const map of [
  seedToSoil,
  soilToFertilizer,
  fertilizerToWater,
  waterToLight,
  lightToTemp,
  tempToHumidity,
  humidityToLocation,
]) {
  map.shift();
}

function cleanInput(o: number[]): boolean {
  return o.length === 3;
}
function orderBySource(a: number[], b: number[]): number {
  return a[1] - b[1];
}

seedToSoil = seedToSoil.filter(cleanInput);
soilToFertilizer = soilToFertilizer.filter(cleanInput).sort(orderBySource);
fertilizerToWater = fertilizerToWater.filter(cleanInput);
waterToLight = waterToLight.filter(cleanInput);
lightToTemp = lightToTemp.filter(cleanInput);
tempToHumidity = tempToHumidity.filter(cleanInput);
humidityToLocation = humidityToLocation.filter(cleanInput);

/**
 * Given a source input and a sorted list of maps, calculate the destination value
 * @param input
 * @param maps in the form of [[dest, sourceFrom, sourceTo]]
 * @returns
 */
function getMapResult(input: number, maps: number[][]): number {
  // Get the map corresponding to number
  let mapped = -1;
  for (const map of maps) {
    const sourceFrom = map[1];
    const sourceTo = map[1] + map[2] - 1;
    if (input >= sourceFrom && input <= sourceTo) {
      mapped = map[0] + input - sourceFrom;
    }
  }
  if (mapped > -1) return mapped;
  return input;
}

let minimalLocation = Number.MAX_VALUE;

for (const pair of seedsPairs) {
  trace(JSON.stringify(pair));
  const to = pair[0] + pair[1] - 1;
  for (let seed = pair[0]; seed < to; seed++) {
    const soil = getMapResult(seed, seedToSoil);
    const fert = getMapResult(soil, soilToFertilizer);
    const water = getMapResult(fert, fertilizerToWater);
    const light = getMapResult(water, waterToLight);
    const temp = getMapResult(light, lightToTemp);
    const hum = getMapResult(temp, tempToHumidity);
    const loc = getMapResult(hum, humidityToLocation);
    if (loc < minimalLocation) minimalLocation = loc;
  }
}

trace(minimalLocation);

// VISUALIZATION
trace("VISUALIZATION");
const steps = [
  { name: "Seeds", map: seedToSoil },
  { name: "Soil", map: soilToFertilizer },
  { name: "Fertilizer", map: fertilizerToWater },
  { name: "Water", map: waterToLight },
  { name: "Light", map: lightToTemp },
  { name: "Temperature", map: tempToHumidity },
  { name: "Humidity", map: humidityToLocation },
  { name: "Location", map: [[0, 0, 0]] },
];

const seed = {
  index: 0,
  step: 0,
  value: seeds[0],
};

const x = 100;
const speed = 10;
let frames = 1;

cls();
function TIC() {
  ++frames;
  const offset = 15;
  const lineLen = 100;
  let y = 1;

  if (frames % speed === 0) {
    seed.value = getMapResult(seed.value, steps[seed.step].map);
    ++seed.step;
    if (seed.step >= steps.length) {
      seed.step = 0;
      if (++seed.index >= seeds.length) {
        seed.index = 0;
      }
      seed.value = seeds[seed.index];
    }

    for (let x = 0; x < 240; ++x) {
      for (let y = 0; y < 136; ++y) {
        const c = pix(x, y);
        if (c >= 12) {
          pix(x, y, c + 1);
        }
      }
    }
  }

  rect(200, 0, 50, 136, 0);

  for (const [i, step] of steps.entries()) {
    print(step.name, 1, y, i + 2);
    line(100, y + 2, x + lineLen, y + 2, i + 2);
    y += offset;
  }

  const yOffset = ((frames % speed) / speed) * 12;
  circ(seed.value + x, seed.step * offset + 2 + yOffset, 2, 12);
  print(seed.value, x + lineLen + 5, seed.step * offset + yOffset, 12);
}
