if (window.IS_DEV) {
  const source = new EventSource('/esbuild');
  source.addEventListener('change', () => location.reload());
}

const xmlns = 'http://www.w3.org/2000/svg';
const svg = document.querySelector('svg');

const hex = {
  inradius: 8.66,
  circumradius: 10,
}

const horzSpacing = hex.inradius;
const vertSpacing = hex.circumradius * 3 / 2;


function toKey({ q, r, s, t = 0 } = {}) {
  return `${[q, r, s, t]}`;
}

function fromKey(key) {
  const split = key.split(',');
  return { q: +split[0], r: +split[1], s: +split[2], t: +(split[3] || 1) };
}

function sameSigns(a, b) {
  return a > -1 && b > -1 || a < 0 && b < 0;
}

function getNeighbors(coords) {
  // const [q, r, s] = coords.split(',').map(n => +n);
  const { q, r, s, t } = fromKey(coords);

  return [
    toKey({ q: q + 1, r: r, s: s - 1, t }),
    toKey({ q: q - 1, r: r, s: s + 1, t }),
    toKey({ q: q + 1, r: r - 1, s: s, t }),
    toKey({ q: q - 1, r: r + 1, s: s, t }),
    toKey({ q: q, r: r + 1, s: s - 1, t }),
    toKey({ q: q, r: r - 1, s: s + 1, t }),
  ]
}

function generateRadialCoordsRect({ rows, columns, odd = false, equal = true } = {}, { q = 0, r = 0, s = 0 } = {}) {
  const list = new Map();

  for (let row = 0; row < rows; row++) {
    const alternating = row % 2;
    const dr = row;

    for (let col = 0; col < columns; col++) {
      let dq = -(alternating + row) / 2 + alternating - col;
      let ds = -(row + alternating) / 2 + col;

      if (odd) {
        dq = dq - alternating;
        ds = ds + alternating;
      }

      list.set(toKey({ q: q + dq, r: r + dr, s: s + ds }), null);
    }

    if (!equal) {
      if ((odd && !(row % 2)) || (!odd && row % 2)) {
        let dq = -(alternating + row) / 2 + alternating - columns;
        let ds = -(row + alternating) / 2 + columns;

        if (odd) {
          dq = dq - alternating;
          ds = ds + alternating;
        }

        list.set(toKey({ q: q + dq, r: r + dr, s: s + ds }), null);
      }
    }
  }

  return list;
}

function addHexText(q, r, s, v) {
  const qText = document.createElementNS(xmlns, 'text');
  qText.textContent = q;
  qText.setAttributeNS(null, 'x', -3);
  qText.setAttributeNS(null, 'y', -3);

  const rText = document.createElementNS(xmlns, 'text');
  rText.textContent = r;
  rText.setAttributeNS(null, 'x', 5);
  rText.setAttributeNS(null, 'y', 1.5);

  const sText = document.createElementNS(xmlns, 'text');
  sText.textContent = s;
  sText.setAttributeNS(null, 'x', -3);
  sText.setAttributeNS(null, 'y', 5);

  const vText = document.createElementNS(xmlns, 'text');
  vText.textContent = v;
  vText.style.fill = 'red';
  vText.setAttributeNS(null, 'y', 1);
  vText.setAttributeNS(null, 'x', -2);

  return [qText, rText, sText, vText];
}

function radialToScreenCoords({ q, r, s }) {
  let x;

  if (q === s)
    x = 0;
  else if (sameSigns(q, s))
    x = Math.abs(q - s);
  else
    x = Math.abs(q) + Math.abs(s);

  x = (q > s ? -1 : 1) * x * horzSpacing;
  y = r * vertSpacing;

  return { x, y };
}

function drawHexes(el, list, renderText = false) {
  for ([key, v] of list) {
    // const [q, r, s] = key.split(',').map(n => +n);
    const { q, r, s, t } = fromKey(key);
    const { x, y } = radialToScreenCoords({ q, r, s });

    const cell = document.createElementNS(xmlns, 'g');
    cell.setAttributeNS(null, 'transform', `translate(${x}, ${y})`);

    const use = document.createElementNS(xmlns, 'use');
    use.setAttributeNS(null, 'href', '#hex');
    cell.appendChild(use);

    if (renderText) addHexText(q, r, s, t).forEach(txt => cell.appendChild(txt));

    list.set(key, cell);
    el.appendChild(cell);
  }
}

function translateRadialCoords({ q, r, s }, direction, distance = 1) {
  return {
    q: q + direction.q * distance,
    r: r + direction.r * distance,
    s: s + direction.s * distance
  };
}

function generateRadialCoords(l, { q, r, s, t = 0 } = {}, { left, top, right, bottom }, offset) {
  const origin = toKey({ q, r, s, t });
  const list = new Map(l);

  list.set(origin, t);
  let queue = [origin];

  while (queue.length > 0) {
    const v = queue.shift();

    getNeighbors(v).forEach(w => {
      // const [wq, wr, ws] = w.split(',').map(n => +n);
      const { q: wq, r: wr, s: ws } = fromKey(w);
      const rDist = Math.abs(wr - r);
      const alternating = rDist % 2;
      const dr = (rDist + alternating) / 2;

      const dLeft = ['right', 'both'].includes(offset) ? left - alternating : left;
      const dRight = ['left', 'both'].includes(offset) ? right - alternating : right;

      if ([
        !list.has(w),
        wr < bottom + r && wr > -top + r,
        wq > -dRight + q - dr && wq < dLeft + q + dr,
        ws > -dLeft + s - dr && ws < dRight + s + dr,
      ].every(v => v)) {
        list.set(w, dr);
        queue.push(w);
      }
    });
  }

  return list;
}

function translateCoords(map, translator) {
  const translated = new Map();

  for ([key, val] of map) {
    // const [q, r, s] = key.split(',').map(n => +n);
    const { q, r, s, t } = fromKey(key);
    translated.set(toKey(translator({ q, r, s, t })), val);
  }

  return translated;
}

document.querySelectorAll('[name="select-elevation"]').forEach(el => {
  const gameboard = document.querySelector('.gameboard');

  el.addEventListener('change', function (e) {
    gameboard.dataset.viewElevation = this.value
  });
});

// function placeBuilding(buildingSelector, mapsheetSelector) {
//   const building = svg.querySelector(buildingSelector);
//   const bld2grid = document.createElementNS(xmlns, 'g');
//   const bld2origin = { q: 0, r: 0, s: 0 };

//   const bld2map2 = svg.querySelector(`${mapsheetSelector} ${buildingSelector}`);
//   const [q, r, s] = bld2map2.dataset.placement.split(',').map(n => +n);
//   const map2bld2place = { q, r, s };

//   bld2hexes = building.querySelector('[data-grid-footprint]').dataset.gridFootprint.split(':').map(coords => {
//     const [q, r, s] = coords.split(',').map(n => +n);
//     const { q: tq, r: tr, s: ts } = translateRadialCoords({ q, r, s }, map2bld2place);

//     return [toKey({ q: tq, r: tr, s: ts }), null];
//   });

//   const bld2screenCoords = radialToScreenCoords(translateRadialCoords(bld2origin, map2bld2place));
//   const bld2structure = document.createElementNS(xmlns, 'g');
//   bld2structure.setAttributeNS(null, 'transform', `translate(${bld2screenCoords.x}, ${bld2screenCoords.y})`)

//   building.querySelectorAll('[data-grid-footprint] > *').forEach(el => {
//     const use = document.createElementNS(xmlns, 'use');
//     use.setAttributeNS(null, 'href', `#${el.id}`);
//     el.classList.forEach(className => use.classList.add(className));
//     bld2structure.appendChild(use);
//   });

//   drawHexes(bld2grid, new Map(bld2hexes), true);

//   const bld2elvBasement = bld2grid.cloneNode(true);
//   bld2elvBasement.classList.add('elevation-basement');
//   bld2map2.appendChild(bld2elvBasement);

//   const bld2elv1 = bld2grid.cloneNode(true);
//   bld2elv1.classList.add('elevation-0');
//   bld2map2.appendChild(bld2elv1);

//   const bld2elv2 = bld2grid.cloneNode(true);
//   bld2elv2.classList.add('elevation-1');
//   bld2map2.appendChild(bld2elv2);

//   const bld2elvRoof = bld2grid.cloneNode(true);
//   bld2elvRoof.classList.add('elevation-roof');
//   bld2map2.appendChild(bld2elvRoof);

//   bld2map2.appendChild(bld2structure);
// }

const buildingHexes = {};

buildingHexes.bld1 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 3, top: 5, right: 3, bottom: 5 },
  'both'
);

buildingHexes.bld2 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 3, top: 5, right: 3, bottom: 5 },
  'both'
);

buildingHexes.bld2 = generateRadialCoords(
  buildingHexes.bld2,
  translateRadialCoords({ q: 0, r: 0, s: 0 }, { q: 1, r: 0, s: -1 }, 3),
  { left: 1, top: 2, right: 1, bottom: 4 },
  'right'
);

buildingHexes.bld2 = generateRadialCoords(
  buildingHexes.bld2,
  translateRadialCoords({ q: 0, r: 0, s: 0 }, { q: 1, r: 0, s: -1 }, -3),
  { left: 1, top: 2, right: 1, bottom: 4 },
  'left'
);

buildingHexes.bld3 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 2, top: 3, right: 2, bottom: 4 }
);

buildingHexes.bld4 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 2, top: 4, right: 3, bottom: 5 },
  'left'
);

buildingHexes.bld5 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 5, top: 3, right: 4, bottom: 2 }
);

buildingHexes.bld6 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 1, top: 5, right: 2, bottom: 4 }
);

buildingHexes.bld7 = generateRadialCoords(
  new Map(),
  { q: 0, r: 0, s: 0 },
  { left: 7, top: 4, right: 7, bottom: 3 },
  'left'
);

buildingHexes.bld7 = generateRadialCoords(
  buildingHexes.bld7,
  { q: 1, r: -4, s: 3 },
  { left: 5, top: 1, right: 6, bottom: 1 }
);

buildingHexes.bld7 = generateRadialCoords(
  buildingHexes.bld7,
  { q: 5, r: 3, s: -8 },
  { left: 1, top: 1, right: 2, bottom: 1 }
);

buildingHexes.bld7 = generateRadialCoords(
  buildingHexes.bld7,
  { q: -4, r: 3, s: 1 },
  { left: 3, top: 1, right: 4, bottom: 1 }
);

const grid = generateRadialCoordsRect({ rows: 25, columns: 33 }, { q: 22, r: -12, s: -10 });
// const grid = generateRadialCoordsRect({ rows: 52, columns: 33 }, translateRadialCoords({ q: 22, r: -12, s: -10 }, { q: 1, r: -2, s: 1 }, 7));

const mapsheet1BuildingCoords = [
  translateCoords(buildingHexes.bld2, ({ q, r, s }) => ({ q: q + 7, r: r + 7, s: s - 14 })),
  translateCoords(buildingHexes.bld4, ({ q, r, s }) => ({ q: -s + 14, r: -r - 6, s: -q - 8 })),
  translateCoords(buildingHexes.bld3, ({ q, r, s }) => ({ q: q - 6, r: r - 6, s: s + 12 })),
  translateCoords(buildingHexes.bld6, ({ q, r, s }) => ({ q: -s - 12, r: -r + 7, s: -q + 5 })),
  generateRadialCoords(new Map(), { q: 0, r: 0, s: 0 }, { left: 4, top: 5, right: 3, bottom: 5 }),
];

const mapsheet2BuildingCoords = [
  translateCoords(buildingHexes.bld1, ({ q, r, s }) => ({ q: q, r: r + 7, s: s - 7 })),
  translateCoords(buildingHexes.bld2, ({ q, r, s }) => ({ q: q + 7, r: r + 7, s: s - 14 })),
  translateCoords(buildingHexes.bld3, ({ q, r, s }) => ({ q: q - 14, r: r + 5, s: s + 9 })),
  translateCoords(buildingHexes.bld4, ({ q, r, s }) => ({ q: q - 8, r: r + 6, s: s + 2 })),
  translateCoords(buildingHexes.bld5, ({ q, r, s }) => ({ q: q + 13, r: r - 6, s: s - 7 })),
  translateCoords(buildingHexes.bld6, ({ q, r, s }) => ({ q: q + 7, r: r - 6, s: s - 1 })),
  translateCoords(buildingHexes.bld7, ({ q, r, s }) => ({ q: q - 6, r: r - 5, s: s + 11 })),
];

const mapsheet3BuildingCoords = [
  translateCoords(buildingHexes.bld1, ({ q, r, s }) => ({ q: q - 2, r: r - 5, s: s + 7 })),
  translateCoords(buildingHexes.bld2, ({ q, r, s }) => ({ q: -s + 9, r: -r - 6, s: -q - 3 })),
  translateCoords(buildingHexes.bld3, ({ q, r, s }) => ({ q: -s + 17, r: -r - 7, s: -q - 10 })),
  translateCoords(buildingHexes.bld4, ({ q, r, s }) => ({ q: q - 9, r: r - 6, s: s + 15 })),
  translateCoords(buildingHexes.bld5, ({ q, r, s }) => ({ q: q + 6, r: r + 8, s: s - 14 })),
  translateCoords(buildingHexes.bld6, ({ q, r, s }) => ({ q: -s + 1, r: -r + 6, s: -q - 7 })),
  translateCoords(buildingHexes.bld7, ({ q, r, s }) => ({ q: q - 12, r: r + 8, s: s + 4 })),
]

const mapsheetHexCoords = generateRadialCoords(new Map(), { q: 0, r: 0, s: 0 }, { left: 17, top: 13, right: 17, bottom: 14 }, 'left');

const mapsheet1hexCoords = new Map(mapsheetHexCoords);
const mapsheet2hexCoords = new Map(mapsheetHexCoords);
const mapsheet3hexCoords = new Map(mapsheetHexCoords);

mapsheet1BuildingCoords.forEach(building => {
  for ([coords, v] of building) mapsheet1hexCoords.delete(coords);
});

mapsheet2BuildingCoords.forEach(building => {
  for ([coords, v] of building) mapsheet2hexCoords.delete(coords);
});

mapsheet3BuildingCoords.forEach(building => {
  for ([coords, v] of building) mapsheet3hexCoords.delete(coords);
});

const gameboard = svg.querySelector('.gameboard');

let mapsheet1 = {
  id: 'mapsheet1',
  grid: mapsheet1hexCoords,
  buildings: mapsheet1BuildingCoords
};

let mapsheet2 = {
  id: 'mapsheet2',
  grid: mapsheet2hexCoords,
  buildings: mapsheet2BuildingCoords
};

let mapsheet3 = {
  id: 'mapsheet3',
  grid: mapsheet3hexCoords,
  buildings: mapsheet3BuildingCoords
};

function drawMapsheet(gameboard, { id, grid, buildings }) {
  const container = document.createElementNS(xmlns, 'g');
  container.id = id;
  gameboard.appendChild(container);

  const gridContainer = document.createElementNS(xmlns, 'g');
  gridContainer.classList.add('elevation-0');
  container.appendChild(gridContainer);
  drawHexes(gridContainer, grid, true);

  const buildingHexes = buildings.reduce((acc, buildingCoords, index) => {
    const buildingContainer = document.createElementNS(xmlns, 'g');
    buildingContainer.classList.add(`building`);
    buildingContainer.classList.add(`building${index}`);
    container.appendChild(buildingContainer);

    [-1, 0, 1].forEach(elevationLevel => {
      const hexContainer = document.createElementNS(xmlns, 'g');
      hexContainer.classList.add(`elevation-${elevationLevel === -1 ? 'basement' : elevationLevel}`);
      buildingContainer.appendChild(hexContainer);

      const hexes = translateCoords(buildingCoords, ({ q, r, s }) => ({ q, r, s, t: elevationLevel }));
      drawHexes(hexContainer, hexes, true);
      acc = new Map([...acc, ...hexes]);
    });

    return acc;
  }, new Map());

  return new Map([...grid, ...buildingHexes]);
}

// const mapsheetHexCoords = generateRadialCoords(
//   new Map(),
//   { q: 0, r: 0, s: 0 },
//   { left: 17, top: 13, right: 17, bottom: 14 },
//   'left'
// );

function drawScenario1() {
  const northMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q + 7, r: r - 14, s: s + 7 }));
  }

  const southMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q - 6, r: r + 12, s: s - 6 }));
  }

  const westMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q + 16, r, s: s - 16 }));
  }

  const eastMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q - 17, r, s: s + 17 }));
  }

  mapsheet2.grid = westMapsheet(mapsheet2.grid);
  mapsheet2.buildings = mapsheet2.buildings.map(westMapsheet);
  mapsheet2 = drawMapsheet(gameboard, mapsheet2);

  mapsheet3.grid = eastMapsheet(mapsheet3.grid);
  mapsheet3.buildings = mapsheet3.buildings.map(eastMapsheet);
  mapsheet3 = drawMapsheet(gameboard, mapsheet3);

  return new Map([...mapsheet2, ...mapsheet3]);
}

function drawScenario2() {
  const northMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q + 13, r: r - 26, s: s + 13 }));
  }

  const southMapsheet = function(map) {
    return translateCoords(map, ({ q, r, s }) => ({ q: q - 13, r: r + 26, s: s - 13 }));
  }

  mapsheet1 = drawMapsheet(gameboard, mapsheet1);

  mapsheet2.grid = northMapsheet(mapsheet2.grid);
  mapsheet2.buildings = mapsheet2.buildings.map(northMapsheet);
  mapsheet2 = drawMapsheet(gameboard, mapsheet2);

  mapsheet3.grid = southMapsheet(mapsheet3.grid);
  mapsheet3.buildings = mapsheet3.buildings.map(southMapsheet);
  mapsheet3 = drawMapsheet(gameboard, mapsheet3);

  return new Map([...mapsheet1, ...mapsheet2, ...mapsheet3]);
}

// const scenario1grid = drawScenario1();
// const scenario2grid = drawScenario2();

const horzMapVect = function(map) {
  const direction = 1;
  // right, { q: -1, r: 0, s: 1 }, 33
  // left, { q: 1, r: 0, s: -1 }, 33
  return translateCoords(map, ({ q, r, s }) => ({ q: q - 33 * direction, r, s: s + 33 * direction }));
}
// [-16, 17], [-33, 0, 33], [-49, -16, 17, 50]

const vertMapVect = function(map) {
  const direction = 1;
  // up, { q: 1, r: -2, s: 1 }, 13
  // down, { q: -1, r: 2, s: -1 }, 13
  return translateCoords(map, ({ q, r, s }) => ({ q: q - 13 * direction, r: r + 26 * direction, s: s - 13 * direction }));
}

// [[7],  [[13],  [[14],
//  [-6]]  [0],    [7],
//         [-13]]  [-6]
//                 [-12]]

mapsheet2 = drawMapsheet(gameboard, mapsheet2);

mapsheet3.grid = vertMapVect(mapsheet3.grid);
mapsheet3.buildings = mapsheet3.buildings.map(vertMapVect);
mapsheet3 = drawMapsheet(gameboard, mapsheet3);

const circle = document.createElementNS(xmlns, 'circle');
circle.setAttributeNS(null, 'r', 5);
circle.setAttributeNS(null, 'fill', 'green');
circle.setAttributeNS(null, 'stroke', 'gold');
circle.setAttributeNS(null, 'stroke-width', 1);

const circle1 = circle.cloneNode();
circle1.setAttributeNS(null, 'fill', 'blue');

const circle2 = circle.cloneNode();
circle2.setAttributeNS(null, 'fill', 'red');

// mapsheet2.get('0,0,0,0').appendChild(circle);
// mapsheet2.get('0,6,-6,1').appendChild(circle1);
// mapsheet2.get('0,9,-9,0').appendChild(circle2);

function addGroup(container, className) {
  const g = document.createElementNS(xmlns, 'g');
  g.classList.add(className);
  container.appendChild(g);
  return g;
}
