/* global SENTRY_DSN */

import Raven from "raven-js";
import React from "react";
import ReactDOM from "react-dom";
import createMiddleware from "raven-for-redux";
import isButterchurnSupported from "butterchurn/lib/isSupported.min";
import osx from "../skins/MacOSXAqua1-5.wsz";
import topaz from "../skins/TopazAmp1-2.wsz";
import visor from "../skins/Vizor1-01.wsz";
import xmms from "../skins/XMMS-Turquoise.wsz";
import zaxon from "../skins/ZaxonRemake1-0.wsz";
import green from "../skins/Green-Dimension-V2.wsz";
import base from "../skins/base-2.91-png.wsz";
import internetArchive from "../skins/Internet-Archive.wsz";
import screenshotInitialState from "./screenshotInitialState";
import partialButterchurnOptions from "./components/MilkdropWindow/options";
import { WINDOWS } from "./constants";
import * as Selectors from "./selectors";

import WebampLazy from "./webampLazy";
import WebampIcon from "./WebampIcon";
import enableMediaSession from "./mediaSession";
import {
  STEP_MARQUEE,
  UPDATE_TIME_ELAPSED,
  UPDATE_WINDOW_POSITIONS,
  SET_VOLUME,
  SET_BALANCE,
  SET_BAND_VALUE,
  DISABLE_MARQUEE,
  TOGGLE_REPEAT,
  TOGGLE_SHUFFLE,
  SET_EQ_AUTO,
  SET_DUMMY_VIZ_DATA
} from "./actionTypes";

import { loadFilesFromReferences } from "./actionCreators";

import {
  skinUrl as configSkinUrl,
  initialTracks,
  initialState,
  disableMarquee
} from "./config";

import { bindToIndexedDB } from "./indexedDB";

const DEFAULT_DOCUMENT_TITLE = document.title;

const NOISY_ACTION_TYPES = new Set([
  STEP_MARQUEE,
  UPDATE_TIME_ELAPSED,
  UPDATE_WINDOW_POSITIONS,
  SET_VOLUME,
  SET_BALANCE,
  SET_BAND_VALUE
]);

const MIN_MILKDROP_WIDTH = 725;

let screenshot = false;
let clearState = false;
let useState = false;
let skinUrl = configSkinUrl;
let library = false;
if ("URLSearchParams" in window) {
  const params = new URLSearchParams(location.search);
  screenshot = params.get("screenshot");
  library = Boolean(params.get("library"));
  // The default skin CSS baked into the JS library does not have full Media
  // Library support. If we are going to show the library we have to load a
  // skin at start time.
  if (library && skinUrl == null) {
    skinUrl = base;
  }
  skinUrl = params.get("skinUrl") || skinUrl;
  clearState = Boolean(params.get("clearState"));
  useState = Boolean(params.get("useState"));
}

function supressDragAndDrop(e) {
  e.preventDefault();
  e.dataTransfer.effectAllowed = "none";
  e.dataTransfer.dropEffect = "none";
}

window.addEventListener("dragenter", supressDragAndDrop);
window.addEventListener("dragover", supressDragAndDrop);
window.addEventListener("drop", supressDragAndDrop);

let lastActionType = null;

// Filter out consecutive common actions
function filterBreadcrumbActions(action) {
  const noisy =
    NOISY_ACTION_TYPES.has(action.type) &&
    NOISY_ACTION_TYPES.has(lastActionType);
  lastActionType = action.type;
  return !noisy;
}

Raven.config(SENTRY_DSN, {
  /* global COMMITHASH */
  release: typeof COMMITHASH !== "undefined" ? COMMITHASH : "DEV"
}).install();

const ravenMiddleware = createMiddleware(Raven, {
  filterBreadcrumbActions,
  stateTransformer: Selectors.getDebugData
});

// Don't prompt user to install Webamp. It's probably not
// what they want.
window.addEventListener("beforeinstallprompt", e => {
  // TODO: we could add this as a context menu item, or something.
  e.preventDefault();
});

// Requires Dropbox's Chooser to be loaded on the page
function genAudioFileUrlsFromDropbox() {
  return new Promise((resolve, reject) => {
    if (window.Dropbox == null) {
      reject();
    }
    window.Dropbox.choose({
      success: resolve,
      error: reject,
      linkType: "direct",
      folderselect: false,
      multiselect: true,
      extensions: ["video", "audio"]
    });
  });
}

Raven.context(async () => {
  window.Raven = Raven;
  if (screenshot) {
    document.getElementsByClassName("about")[0].style.visibility = "hidden";
  }
  if (!WebampLazy.browserIsSupported()) {
    document.getElementById("browser-compatibility").style.display = "block";
    document.getElementById("app").style.visibility = "hidden";
    return;
  }

  let __butterchurnOptions = null;
  let __initialWindowLayout = null;
  if (isButterchurnSupported()) {
    const startWithMilkdropHidden =
      library ||
      document.body.clientWidth < MIN_MILKDROP_WIDTH ||
      skinUrl != null ||
      screenshot;

    __butterchurnOptions = {
      ...partialButterchurnOptions,
      butterchurnOpen: !startWithMilkdropHidden
    };

    if (startWithMilkdropHidden) {
      __initialWindowLayout = {
        [WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
        [WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
        [WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 0] },
        [WINDOWS.MILKDROP]: { position: { x: 0, y: 348 }, size: [0, 0] }
      };
      if (library) {
        __initialWindowLayout[WINDOWS.MEDIA_LIBRARY] = {
          position: { x: 0, y: 348 },
          size: [0, 0]
        };
      }
    } else {
      __initialWindowLayout = {
        [WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
        [WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
        [WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 4] },
        [WINDOWS.MILKDROP]: { position: { x: 275, y: 0 }, size: [7, 12] }
      };
      if (library) {
        __initialWindowLayout[WINDOWS.MEDIA_LIBRARY] = {
          position: { x: 275, y: 0 },
          size: [7, 12]
        };
      }
    }

    document.getElementById("butterchurn-share").style.display = "flex";
  }

  const initialSkin = !skinUrl ? null : { url: skinUrl };

  const webamp = new WebampLazy({
    initialSkin,
    initialTracks: screenshot ? null : initialTracks,
    availableSkins: [
      { url: green, name: "Green Dimension V2" },
      { url: internetArchive, name: "Internet Archive" },
      { url: osx, name: "Mac OSX v1.5 (Aqua)" },
      { url: topaz, name: "TopazAmp" },
      { url: visor, name: "Vizor" },
      { url: xmms, name: "XMMS Turquoise " },
      { url: zaxon, name: "Zaxon Remake" }
    ],
    filePickers: [
      {
        contextMenuName: "Dropbox...",
        filePicker: async () => {
          const files = await genAudioFileUrlsFromDropbox();
          return files.map(file => ({
            url: file.link,
            defaultName: file.name
          }));
        },
        requiresNetwork: true
      }
    ],
    enableHotkeys: true,
    requireJSZip: () =>
      import(/* webpackChunkName: "jszip" */ "jszip/dist/jszip"),
    requireMusicMetadata: () =>
      import(/* webpackChunkName: "music-metadata-browser" */ "music-metadata-browser/dist/index"),
    __enableMediaLibrary: library,
    __initialWindowLayout,
    __initialState: screenshot ? screenshotInitialState : initialState,
    __butterchurnOptions,
    __customMiddlewares: [ravenMiddleware]
  });

  if (disableMarquee || screenshot) {
    webamp.store.dispatch({ type: DISABLE_MARQUEE });
  }
  if (screenshot) {
    window.document.body.style.backgroundColor = "#000";
    webamp.store.dispatch({ type: TOGGLE_REPEAT });
    webamp.store.dispatch({ type: TOGGLE_SHUFFLE });
    webamp.store.dispatch({ type: SET_EQ_AUTO, value: true });
    webamp.store.dispatch({
      type: SET_DUMMY_VIZ_DATA,
      data: {
        0: 11.75,
        8: 11.0625,
        16: 8.5,
        24: 7.3125,
        32: 6.75,
        40: 6.4375,
        48: 6.25,
        56: 5.875,
        64: 5.625,
        72: 5.25,
        80: 5.125,
        88: 4.875,
        96: 4.8125,
        104: 4.375,
        112: 3.625,
        120: 1.5625
      }
    });
  }

  webamp.onTrackDidChange(track => {
    document.title =
      track == null
        ? DEFAULT_DOCUMENT_TITLE
        : `${track.metaData.title} - ${track.metaData.artist}`;
  });

  enableMediaSession(webamp);

  // Expose a file input in the DOM for testing.
  const fileInput = document.createElement("input");
  fileInput.id = "webamp-file-input";
  fileInput.style.display = "none";
  fileInput.type = "file";
  fileInput.value = null;
  fileInput.addEventListener("change", e => {
    webamp.store.dispatch(loadFilesFromReferences(e.target.files));
  });
  document.body.appendChild(fileInput);

  // Expose webamp instance for debugging and integration tests.
  window.__webamp = webamp;

  await bindToIndexedDB(webamp, clearState, useState);

  await webamp.renderWhenReady(document.getElementById("app"));

  ReactDOM.render(
    <WebampIcon webamp={webamp} />,
    document.getElementById("webamp-icon")
  );
});
