import { others } from './svg';
import { cells } from './svg';
import {
  backgroundsArr,
  othersFiles,
  languageSvgStyles,
  myFlagSvgStyles,
  enemyFlagSvgStyles,
  flagStarsStyles,
} from './western-world.utils.constants';
import {
  getPathByCell,
  getImageByUrl,
  getFlagsArray,
  buildImageForCanvasFromHtmlStr,
  getMaxSide,
  getMaskStyles,
} from './western-world.utils.helpers';

export const buildNewSvgImages = ({ allCells, language }) => {
  console.log('buildNewSvgImages...');
  const parser = new DOMParser();
  return Promise.all(
    allCells
      .filter((cell) => cell.id)
      .map((cell) => {
        return Promise.all([
          buildNewSvgImageByCell({ cell, language, withMask: true, parser }).then(({ img, svgTag }) => {
            window.cachedImages[language].svgTags[cell.animatedImage] = svgTag;
            window.cachedImages[language].svgTags[cell.id] = svgTag;
            window.cachedImages[language].svgImagesForCanvas[cell.animatedImage] = img;
            window.cachedImages[language].svgImagesForCanvas[cell.id] = img;
          }),
          buildNewSvgImageByCell({ cell, language, withMask: false, parser }).then(({ img }) => {
            window.cachedImages[language].svgImagesWithoutMasks[cell.animatedImage] = img;
            window.cachedImages[language].svgImagesWithoutMasks[cell.id] = img;
          }),
        ]);
      })
  );
};

export const buildNewSvgImageByCell = ({ cell, language, withMask, parser }) => {
  // get svg image from file and apply offsets;
  const doc = parser.parseFromString(cells[cell.animatedImage].svgPath, 'image/svg+xml');
  const svgEl = doc.querySelector('svg');
  const maxMainSvgViewBox = svgEl.viewBox.baseVal.width;
  svgEl.classList.add(cell.animatedImage);
  const styleElement = svgEl.querySelector('svg > style');
  const styleSvg = `
          ${languageSvgStyles}
          ${withMask ? getMaskStyles(cell) : ''}
          ${cells[cell.animatedImage].scssPath}
  `;
  styleElement.insertAdjacentHTML('beforeend', styleSvg);

  // create new <g> and move all content to it to apply mask;
  const gElement = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  withMask && gElement.setAttribute('mask', `url(#mask-${cell.id})`);
  gElement.setAttribute('class', language);
  const allSvgImageContent = svgEl.querySelectorAll('svg > *:not(style)');
  [...allSvgImageContent].forEach((el) => gElement.appendChild(el));

  const maxCellSize = getMaxSide(cell);
  const cellPath = getPathByCell(cell, maxCellSize, maxMainSvgViewBox);
  const mask = `
          <mask id="mask-${cell.id}">
            <use xlink:href="#path-border-${cell.id}" class="use-mask"></use>
            <use xlink:href="#additional-mask" class="use-additional-mask"></use>
          </mask>
        `;
  const defsElement = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  defsElement.innerHTML = `
          ${cellPath}
          ${mask}
          ${cells[cell.animatedImage].defs ? cells[cell.animatedImage].defs.map((el) => el.value).join(' ') : ''}
        `;
  svgEl.appendChild(defsElement);

  if (withMask) {
    // create use border path;
    const svgUseBorderElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
    svgUseBorderElement.setAttribute('xlink:href', `#path-border-${cell.id}`);
    svgUseBorderElement.setAttribute('class', 'use-border');
    svgEl.appendChild(svgUseBorderElement);
  }
  svgEl.appendChild(gElement);
  return buildImageForCanvasFromHtmlStr(svgEl.outerHTML).then((img) => {
    img.defs = cells[cell.animatedImage].defs?.map(({ name, type }) => ({ name, type }));
    return { svgTag: svgEl.outerHTML, img };
  });
};

export const parseAndSaveToObjectOtherSvgFile = ({ fileName, html, svgStyles, language, propertyName }) => {
  const parser = new DOMParser();

  const doc = parser.parseFromString(html, 'image/svg+xml');
  const svgEl = doc.querySelector('svg');
  const str = `
    <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10000 10000">
      <style>${svgStyles}</style>
      <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10000 10000" class="${language}">
        <defs>${others[fileName]?.defs ? cells[fileName].defs.map((el) => el.value).join(' ') : ''}</defs>
        ${svgEl.outerHTML}
      </svg>
    </svg>
  `;
  window.cachedImages[language].svgTags[propertyName] = str;
  return buildImageForCanvasFromHtmlStr(str);
};

export const buildOtherSvgImages = ({ language }) => {
  console.log('buildOtherSvgImages...');
  return Promise.all(
    othersFiles.map((fileName) => {
      const cellImport = others[fileName];
      const svgStr = typeof cellImport === 'object' ? cellImport.svgPath : cellImport;
      const scssAnimationStr = typeof cellImport === 'object' ? cellImport.scssPath : '';

      if (fileName === 'flag') {
        return Promise.all(
          [...getFlagsArray('my'), ...getFlagsArray('enemy')].map((el) => {
            const flagSvgStyles = `${el.prefix === 'my' ? myFlagSvgStyles : enemyFlagSvgStyles} ${
              flagStarsStyles[el.index]
            }`;
            return parseAndSaveToObjectOtherSvgFile({
              fileName,
              html: svgStr,
              svgStyles: `${flagSvgStyles} ${scssAnimationStr}`,
              language,
              propertyName: el.name,
            }).then((img) => {
              window.cachedImages[language].svgImagesForCanvas[el.name] = img;
              window.cachedImages[language].svgImagesWithoutMasks[el.name] = img;
            });
          })
        );
      }
      return parseAndSaveToObjectOtherSvgFile({
        html: svgStr,
        svgStyles: `${languageSvgStyles} ${scssAnimationStr}`,
        language,
        propertyName: fileName,
      }).then((img) => {
        window.cachedImages[language].svgImagesForCanvas[fileName] = img;
        window.cachedImages[language].svgImagesWithoutMasks[fileName] = img;
      });
    })
  );
};

export const drawBackgrounds = ({ ctx, BACKGROUND_X, BACKGROUND_Y, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, language }) => {
  console.log('drawBackgrounds...');
  backgroundsArr.forEach((fileName) =>
    ctx.drawImage(
      window.cachedImages[language].svgImagesForCanvas[fileName],
      BACKGROUND_X,
      BACKGROUND_Y,
      BACKGROUND_WIDTH,
      BACKGROUND_HEIGHT
    )
  );
};

export const drawBackgroundTopElements = ({
  ctx,
  BACKGROUND_X,
  BACKGROUND_Y,
  BACKGROUND_WIDTH,
  BACKGROUND_HEIGHT,
  language,
}) => {
  ctx.drawImage(
    window.cachedImages[language].svgImagesForCanvas['background-top-elements'],
    BACKGROUND_X,
    BACKGROUND_Y,
    BACKGROUND_WIDTH,
    BACKGROUND_HEIGHT
  );
};

export const drawNewAdditionalStuff = ({ ctx, SIZE_X_QUALITY, PADDING_LEFT, PADDING_TOP, language }) => {
  console.log('drawNewAdditionalStuff...');
  ctx.drawImage(
    window.cachedImages[language].svgImagesForCanvas['colony-arrows'],
    295 * SIZE_X_QUALITY + PADDING_LEFT,
    145 * SIZE_X_QUALITY + PADDING_TOP,
    1025 * SIZE_X_QUALITY,
    1025 * SIZE_X_QUALITY
  );
};

export const drawFlags = ({ allCells, ctx, game, myIdKey, SIZE_X_QUALITY, PADDING_LEFT, PADDING_TOP, language }) => {
  if (!game.players) {
    return;
  }
  console.log('drawFlags...');
  const myPlayer = game.players[myIdKey];
  const allMyCompanies = myPlayer?.firms;
  const allEnemyCompanies = game.players.order.reduce((previousValue, playerIdKey) => {
    if (playerIdKey === myPlayer?.user?.id_key) {
      return previousValue;
    }
    game.players[playerIdKey].firms.forEach((firmId) => {
      previousValue[firmId] = playerIdKey;
    });
    return previousValue;
  }, {});
  allCells
    .filter((cell) => cell.id)
    .forEach((cell) => {
      const flagX = cell.flag ? cell.flag.x : cell.location.x1 + (cell.location.x2 - cell.location.x1) / 2;
      const flagY = cell.flag ? cell.flag.y : cell.location.y1;
      let flag;
      let avatar;
      if (allEnemyCompanies[cell.id]) {
        flag = window.cachedImages[language].svgImagesForCanvas[`enemy-flag-stars-${game.stocks[cell.id].stars}`];
        avatar = window.cachedImages[language].avatarsMapForCanvas[allEnemyCompanies[cell.id]];
      }
      if (allMyCompanies?.includes(cell.id)) {
        flag = window.cachedImages[language].svgImagesForCanvas[`my-flag-stars-${game.stocks[cell.id].stars}`];
        avatar = window.cachedImages[language].avatarsMapForCanvas[myPlayer.user.id_key];
      }
      if (!flag || !avatar) {
        return;
      }
      ctx.drawImage(
        flag,
        (cell.location.x1 + flagX - 53) * SIZE_X_QUALITY + PADDING_LEFT,
        (cell.location.y1 + flagY - 60) * SIZE_X_QUALITY + PADDING_TOP,
        64 * SIZE_X_QUALITY,
        64 * SIZE_X_QUALITY
      );
      ctx.drawImage(
        avatar,
        (cell.location.x1 + flagX - 22.5) * SIZE_X_QUALITY + PADDING_LEFT,
        (cell.location.y1 + flagY - 35) * SIZE_X_QUALITY + PADDING_TOP,
        15 * SIZE_X_QUALITY,
        15 * SIZE_X_QUALITY
      );
    });
};

export const drawAllNewCells = ({ allCells, ctx, SIZE_X_QUALITY, PADDING_LEFT, PADDING_TOP, language }) => {
  console.log('drawAllNewCells...');
  allCells
    .filter((cell) => cell.id)
    .forEach((cell) => {
      const max = getMaxSide(cell);
      ctx.drawImage(
        window.cachedImages[language].svgImagesForCanvas[cell.id],
        cell.location.x1 * SIZE_X_QUALITY + PADDING_LEFT,
        cell.location.y1 * SIZE_X_QUALITY + PADDING_TOP,
        max * SIZE_X_QUALITY,
        max * SIZE_X_QUALITY
      );
    });
};

let currentPromise;
let isResolved = false;
export const buildPlayerAvatars = ({ avatars, language }) => {
  if (!avatars) {
    return Promise.resolve();
  }

  if (currentPromise && !isResolved) {
    return currentPromise;
  }

  // if currentPromise and all avatars are same;
  if (
    currentPromise &&
    isResolved &&
    avatars.every(({ id_key }) => window.cachedImages[language].avatarsMapForCanvas[id_key])
  ) {
    return currentPromise;
  }

  console.log('refbuild avatars...');
  isResolved = false;
  currentPromise = Promise.all(avatars.map(({ iconBase64 }) => getImageByUrl(iconBase64))).then((data) => {
    isResolved = true;
    data.forEach((image, index) => {
      window.cachedImages[language].avatarsMapForCanvas[avatars[index].id_key] = image;
    });
  });
  return currentPromise;
};
