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

let newSvgImagesResolve;
let otherSvgImagesResolve;

export const images = {
  svgTags: {},
  svgImagesForCanvas: {}, // map HTMLImageElement for canvas;
  avatarsMapForCanvas: {}, // map HTMLImageElement for canvas;
  resolver: {
    all: Promise.all([
      new Promise((resolve) => (newSvgImagesResolve = resolve)),
      new Promise((resolve) => (otherSvgImagesResolve = resolve)),
    ]),
  },
  allImagesProgress: {
    data: {
      all: 0,
      loaded: 0,
    },
    resetLoadingImage() {
      this.data.all = 0;
      this.data.loaded = 0;
    },
    startLoadingImage() {
      this.data.all++;
    },
    endLoadingImage() {
      this.data.loaded++;
    },
  },
};

export const buildNewSvgImages = ({ allCells, language }) => {
  const parser = new DOMParser();
  return Promise.all(
    allCells
      .filter((cell) => cell.id)
      .map((cell) => {
        images.allImagesProgress.startLoadingImage();
        let newHtml = cells[`${cell.animatedImage}.svg`].replace(/\.st([0-9]{1,3})/g, `.${cell.animatedImage}_st$1`);
        newHtml = newHtml.replace(/\"st([0-9]{1,3})/g, `"${cell.animatedImage}_st$1`);
        newHtml = newHtml.replace(/SVGID_([0-9]{1,3})_/g, `${cell.animatedImage}_SVGID_$1_`);

        // get svg image from file and apply offsets;
        const doc = parser.parseFromString(newHtml, '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}
          ${maskStyles}
        `;
        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');
        gElement.setAttribute('mask', `url(#mask-${cell.id})`);
        gElement.setAttribute('class', language);
        const allSvgImageContent = svgEl.querySelectorAll('svg > *:not(style)');
        [...allSvgImageContent].forEach((el) => gElement.appendChild(el));

        // 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');

        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}
        `;
        svgEl.appendChild(defsElement);
        svgEl.appendChild(svgUseBorderElement);
        svgEl.appendChild(gElement);

        images.svgTags[cell.animatedImage] = svgEl.outerHTML;
        images.svgTags[cell.id] = svgEl.outerHTML;

        return buildImageForCanvasFromHtmlStr(svgEl.outerHTML)
          .then((img) => (images.svgImagesForCanvas[cell.id] = img))
          .then(() => images.allImagesProgress.endLoadingImage());
      })
  )
    .then(newSvgImagesResolve)
    .catch(console.log);
};

export const parseAndSaveToObjectOtherSvgFile = ({ 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}">
        ${svgEl.outerHTML}
      </svg>
    </svg>
  `;
  images.svgTags[propertyName] = str;
  return buildImageForCanvasFromHtmlStr(str);
};

export const buildOtherSvgImages = ({ language }) => {
  return Promise.all(
    othersFiles.map((fileName) => {
      images.allImagesProgress.startLoadingImage();
      if (fileName === 'flag.svg') {
        return Promise.all(
          [...getFlagsArray('my'), ...getFlagsArray('enemy')].map((el) => {
            return parseAndSaveToObjectOtherSvgFile({
              html: others[fileName],
              svgStyles: `${el.prefix === 'my' ? myFlagSvgStyles : enemyFlagSvgStyles} ${flagStarsStyles[el.index]}`,
              language,
              propertyName: el.name,
            }).then((img) => (images.svgImagesForCanvas[el.name] = img));
          })
        ).then(() => images.allImagesProgress.endLoadingImage());
      }
      return parseAndSaveToObjectOtherSvgFile({
        html: others[fileName],
        svgStyles: languageSvgStyles,
        language,
        propertyName: fileName,
      })
        .then((img) => (images.svgImagesForCanvas[fileName] = img))
        .then(() => images.allImagesProgress.endLoadingImage());
    })
  ).then(otherSvgImagesResolve);
};

export const drawBackgrounds = ({ ctx, BACKGROUND_X, BACKGROUND_Y, BACKGROUND_WIDTH, BACKGROUND_HEIGHT }) => {
  backgroundsArr.forEach((fileName) =>
    ctx.drawImage(images.svgImagesForCanvas[fileName], BACKGROUND_X, BACKGROUND_Y, BACKGROUND_WIDTH, BACKGROUND_HEIGHT)
  );
};

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

export const drawNewAdditionalStuff = ({ ctx, SIZE_X_QUALITY, PADDING_LEFT, PADDING_TOP }) => {
  ctx.drawImage(
    images.svgImagesForCanvas['colony-arrows.svg'],
    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 }) => {
  if (!game.players) {
    return;
  }
  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 = images.svgImagesForCanvas[`enemy-flag-stars-${game.stocks[cell.id].stars}`];
        avatar = images.avatarsMapForCanvas[allEnemyCompanies[cell.id]];
      }
      if (allMyCompanies?.includes(cell.id)) {
        flag = images.svgImagesForCanvas[`my-flag-stars-${game.stocks[cell.id].stars}`];
        avatar = images.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 }) => {
  allCells
    .filter((cell) => cell.id)
    .forEach((cell) => {
      const max = getMaxSide(cell);
      ctx.drawImage(
        images.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
      );
    });
};

export const buildPlayerAvatars = ({ avatars }) => {
  if (!avatars) {
    return Promise.resolve();
  }
  return Promise.all(avatars.map(({ iconBase64 }) => getImageByUrl(iconBase64))).then((data) => {
    data.forEach((image, index) => {
      images.avatarsMapForCanvas[avatars[index].id_key] = image;
    });
  });
};
