import { getConfig } from '@scrabble-solver/configs';
import { Game, Locale } from '@scrabble-solver/types';

import {
  PLAIN_TILES_COLOR_DEFAULT,
  PLAIN_TILES_PADDING_HORIZONTAL,
  PLAIN_TILES_PADDING_VERTICAL,
  PLAIN_TILES_POINTS_COLORS,
  PLAIN_TILES_TILE_MARGIN,
  PLAIN_TILES_TILE_MAX_ROTATE,
  PLAIN_TILES_TILE_MAX_SCATTER,
  PLAIN_TILES_TILE_SIZE,
} from '@/parameters';

import type { CreatePlainTileOptions, CreatePlainTilesOptions, PlainTile } from './types';

export const createPlainTiles = ({ color, content, showPoints }: CreatePlainTilesOptions): PlainTile[] => {
  const rows = content.map((words, rowIndex) => {
    return words.map((word, wordIndex) => {
      const cellOffset = words.slice(0, wordIndex).reduce((result, { length }) => result + length + ' '.length, 0);
      const characters = word.split('');

      return characters.map((character, cellIndex) => {
        return createPlainTile({
          cellIndex: cellOffset + cellIndex,
          character,
          color,
          rowIndex,
          showPoints,
        });
      });
    });
  });

  const tiles = rows.flat(2);
  return tiles;
};

export const createPlainTile = ({
  cellIndex,
  character,
  color,
  rowIndex,
  showPoints,
}: CreatePlainTileOptions): PlainTile => {
  const configPoints = getConfig(Game.Literaki, Locale.EN_US).getCharacterPoints(character.toLowerCase());
  const points = showPoints ? configPoints : undefined;
  const defaultColor =
    typeof configPoints === 'number' ? PLAIN_TILES_POINTS_COLORS[configPoints] : PLAIN_TILES_COLOR_DEFAULT;
  const x = getX(cellIndex) + PLAIN_TILES_TILE_SIZE / 2;
  const y = getY(0) + PLAIN_TILES_TILE_SIZE / 2;

  return {
    character,
    color: color || defaultColor,
    points,
    size: PLAIN_TILES_TILE_SIZE,
    transform: `rotate(${randomize(0, PLAIN_TILES_TILE_MAX_ROTATE)}, ${x}, ${y})`,
    x: randomize(getX(cellIndex), PLAIN_TILES_TILE_MAX_SCATTER),
    y: randomize(getY(rowIndex), PLAIN_TILES_TILE_MAX_SCATTER),
  };
};

export const getViewbox = (content: string[][]): string => {
  const longestRowLength = content.reduce((result, words) => {
    const wordsLength = words.reduce((sum, word) => sum + word.length, 0);
    const rowLength = wordsLength + Math.max(words.length - 1, 0);
    return Math.max(result, rowLength);
  }, 0);
  const width =
    longestRowLength * (PLAIN_TILES_TILE_SIZE + PLAIN_TILES_TILE_MARGIN) -
    (longestRowLength === 0 ? 0 : PLAIN_TILES_TILE_MARGIN);
  const height =
    content.length * (PLAIN_TILES_TILE_SIZE + PLAIN_TILES_TILE_MARGIN) -
    (content.length === 0 ? 0 : PLAIN_TILES_TILE_MARGIN);

  return `0 0 ${width} ${height}`;
};

export const getX = (index: number): number => {
  return PLAIN_TILES_PADDING_HORIZONTAL + index * (PLAIN_TILES_TILE_SIZE + PLAIN_TILES_TILE_MARGIN);
};

export const getY = (index: number): number => {
  return PLAIN_TILES_PADDING_VERTICAL + index * (PLAIN_TILES_TILE_SIZE + PLAIN_TILES_TILE_MARGIN);
};

export const randomize = (value: number, maxChange: number): number => {
  return value + maxChange * 2 * (0.5 - Math.random());
};
