/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
'use strict';

import EventListenerManager from '/extlib/EventListenerManager.js';

import {
  configs,
  log as internalLogger,
  isWindows,
} from './common.js';
import * as ApiTabs from '/common/api-tabs.js';

// eslint-disable-next-line no-unused-vars
function log(...args) {
  internalLogger('common/contextual-identities', ...args);
}

const mContextualIdentities = new Map();
let mIsObserving = false;

export function get(id) {
  return mContextualIdentities.get(id);
}

export function getIdFromName(name) {
  for (const identity of mContextualIdentities.values()) {
    if (identity.name.toLowerCase() == name.toLowerCase())
      return identity.cookieStoreId;
  }
  return null;
}

// Respect container type stored by Container Bookmarks
// https://addons.mozilla.org/firefox/addon/container-bookmarks/
export function getIdFromBookmark(bookmark) {
  const containerMatcher = new RegExp(`#${configs.containerRedirectKey}-(.+)$`);
  const matchedContainer = bookmark.url.match(containerMatcher);
  if (!matchedContainer)
    return {};

  const idPart = matchedContainer[matchedContainer.length-1];
  const url    = bookmark.url.replace(containerMatcher, '');

  // old method
  const identity = mContextualIdentities.get(decodeURIComponent(idPart));
  if (identity) {
    return {
      cookieStoreId: identity.cookieStoreId,
      url,
    };
  }

  for (const [cookieStoreId, identity] of mContextualIdentities.entries()) {
    if (idPart != encodeURIComponent(identity.name.toLowerCase().replace(/\s/g, '-')))
      continue;
    return {
      cookieStoreId,
      url,
    };
  }

  return {};
}

export function getColorInfo() {
  const colors = {};
  const customColors = [];
  forEach(identity => {
    if (!identity.colorCode)
      return;
    let colorValue = identity.colorCode;
    if (identity.color) {
      const customColor = `--contextual-identity-color-${identity.color}`;
      customColors.push(`${customColor}: ${identity.colorCode};`);
      colorValue = `var(${customColor})`;
    }
    colors[identity.cookieStoreId] = colorValue;
  });

  return {
    colors,
    colorDeclarations: customColors.length > 0 ? `:root { ${customColors.join('\n')} }` : ''
  };
}

export function getCount() {
  return mContextualIdentities.size;
}

export function forEach(callback) {
  for (const identity of mContextualIdentities.values()) {
    callback(identity);
  }
}

if (browser.contextualIdentities) { // already granted
  browser.contextualIdentities.onCreated.addListener(onContextualIdentityCreated);
  browser.contextualIdentities.onRemoved.addListener(onContextualIdentityRemoved);
  browser.contextualIdentities.onUpdated.addListener(onContextualIdentityUpdated);
  mIsObserving = true;
}

export function startObserve() {
  if (!browser.contextualIdentities ||
      mIsObserving)
    return;
  mIsObserving = true;
  browser.contextualIdentities.onCreated.addListener(onContextualIdentityCreated);
  browser.contextualIdentities.onRemoved.addListener(onContextualIdentityRemoved);
  browser.contextualIdentities.onUpdated.addListener(onContextualIdentityUpdated);
}

export function endObserve() {
  if (!browser.contextualIdentities ||
      !mIsObserving)
    return;
  browser.contextualIdentities.onCreated.removeListener(onContextualIdentityCreated);
  browser.contextualIdentities.onRemoved.removeListener(onContextualIdentityRemoved);
  browser.contextualIdentities.onUpdated.removeListener(onContextualIdentityUpdated);
}

export async function init() {
  if (!browser.contextualIdentities)
    return;
  const identities = await browser.contextualIdentities.query({}).catch(ApiTabs.createErrorHandler());
  for (const identity of identities) {
    mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
  }
}

function fixupIcon(identity) {
  if (identity.icon && identity.color)
    identity.iconUrl = `/resources/icons/contextual-identities/${identity.icon}.svg#${safeColor(identity.color)}`;
  return identity;
}

const mDarkModeMedia = window.matchMedia('(prefers-color-scheme: dark)');
mDarkModeMedia.addListener(async _event => {
  await init();
  forEach(identity => onContextualIdentityUpdated({ contextualIdentity: identity }));
});

function safeColor(color) {
  switch (color) {
    case 'blue':
    case 'turquoise':
    case 'green':
    case 'yellow':
    case 'orange':
    case 'red':
    case 'pink':
    case 'purple':
      return color;

    case 'toolbar':
    default:
      return !isWindows() && mDarkModeMedia.matches ? 'toolbar-dark' : 'toolbar-light';
  }
}

export const onUpdated = new EventListenerManager();

function onContextualIdentityCreated(createdInfo) {
  if (!mIsObserving)
    return;

  const identity = createdInfo.contextualIdentity;
  mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
  onUpdated.dispatch();
}

function onContextualIdentityRemoved(removedInfo) {
  if (!mIsObserving)
    return;

  const identity = removedInfo.contextualIdentity;
  delete mContextualIdentities.delete(identity.cookieStoreId);
  onUpdated.dispatch();
}

function onContextualIdentityUpdated(updatedInfo) {
  if (!mIsObserving)
    return;

  const identity = updatedInfo.contextualIdentity;
  mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
  onUpdated.dispatch();
}


export function generateMenuItems({ hasDefault } = {}) {
  const fragment = document.createDocumentFragment();

  if (hasDefault) {
    const defaultCotnainerItem = document.createElement('li');
    defaultCotnainerItem.dataset.value = 'firefox-default';
    defaultCotnainerItem.textContent = browser.i18n.getMessage('tabbar_newTabWithContexualIdentity_default');
    fragment.appendChild(defaultCotnainerItem);

    const separator = document.createElement('li');
    separator.classList.add('separator');
    fragment.appendChild(separator);
  }

  forEach(identity => {
    const item = document.createElement('li');
    item.dataset.value = identity.cookieStoreId;
    item.textContent = identity.name;
    item.dataset.icon = identity.iconUrl;
    fragment.appendChild(item);
  });

  return fragment;
}
