import _ from "underscore";
import * as Q_DEPRECATED from "metabase/lib/query";
import Utils from "metabase/lib/utils";
import * as Urls from "metabase/lib/urls";

import { CardApi } from "metabase/services";

export function createCard(name = null) {
  return {
    name: name,
    display: "table",
    visualization_settings: {},
    dataset_query: {},
  };
}

// start a new card using the given query type and optional database and table selections
export function startNewCard(type, databaseId, tableId) {
  // create a brand new card to work from
  const card = createCard();
  card.dataset_query = Q_DEPRECATED.createQuery(type, databaseId, tableId);

  return card;
}

// load a card either by ID or from a base64 serialization.  if both are present then they are merged, which the serialized version taking precedence
// TODO: move to redux
export async function loadCard(cardId) {
  try {
    return await CardApi.get({ cardId: cardId });
  } catch (error) {
    console.log("error loading card", error);
    throw error;
  }
}

// TODO Atte Keinänen 5/31/17 Deprecated, we should migrate existing references to this method to `question.isCardDirty`
// predicate function that dermines if a given card is "dirty" compared to the last known version of the card
export function isCardDirty(card, originalCard) {
  // The rules:
  //   - if it's new, then it's dirty when
  //       1) there is a database/table chosen or
  //       2) when there is any content on the native query
  //   - if it's saved, then it's dirty when
  //       1) the current card doesn't match the last saved version

  if (!card) {
    return false;
  } else if (!card.id) {
    if (card.dataset_query.query && card.dataset_query.query["source-table"]) {
      return true;
    } else if (
      card.dataset_query.native &&
      !_.isEmpty(card.dataset_query.native.query)
    ) {
      return true;
    } else {
      return false;
    }
  } else {
    const origCardSerialized = originalCard
      ? serializeCardForUrl(originalCard)
      : null;
    const newCardSerialized = card
      ? serializeCardForUrl(_.omit(card, "original_card_id"))
      : null;
    return newCardSerialized !== origCardSerialized;
  }
}

// TODO Atte Keinänen 5/31/17 Deprecated, we should move tests to Questions.spec.js
export function serializeCardForUrl(card) {
  const dataset_query = Utils.copy(card.dataset_query);
  if (dataset_query.query) {
    dataset_query.query = Q_DEPRECATED.cleanQuery(dataset_query.query);
  }

  const cardCopy = {
    name: card.name,
    description: card.description,
    dataset_query: dataset_query,
    display: card.display,
    displayIsLocked: card.displayIsLocked,
    parameters: card.parameters,
    visualization_settings: card.visualization_settings,
    original_card_id: card.original_card_id,
  };

  return utf8_to_b64url(JSON.stringify(cardCopy));
}

export function deserializeCardFromUrl(serialized) {
  serialized = serialized.replace(/^#/, "");
  return JSON.parse(b64url_to_utf8(serialized));
}

// escaping before base64 encoding is necessary for non-ASCII characters
// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
export function utf8_to_b64(str) {
  return window.btoa(unescape(encodeURIComponent(str)));
}
export function b64_to_utf8(b64) {
  return decodeURIComponent(escape(window.atob(b64)));
}

// for "URL safe" base64, replace "+" with "-" and "/" with "_" as per RFC 4648
export function utf8_to_b64url(str) {
  return utf8_to_b64(str)
    .replace(/\+/g, "-")
    .replace(/\//g, "_");
}
export function b64url_to_utf8(b64url) {
  return b64_to_utf8(b64url.replace(/-/g, "+").replace(/_/g, "/"));
}

export function urlForCardState(state, dirty) {
  return Urls.question(
    state.cardId,
    state.serializedCard && dirty ? state.serializedCard : "",
  );
}

export function cleanCopyCard(card) {
  const cardCopy = {};
  for (const name in card) {
    if (name.charAt(0) !== "$") {
      cardCopy[name] = card[name];
    }
  }
  return cardCopy;
}
