import { expandedTrackHeight } from '../styles/dimensions';
import { ProjectState, Selection } from '../types';
import CommandProject from './CommandProject';
import initStandardLibrary from './initStandardLibrary';
import { fromSendable, toSendable } from './sandboxTools';

const ctx: Worker = self as any;

const consoleOverride = `
  this.console = {
    assert: () => {},
    clear: () => {},
    context: () => {},
    count: () => {},
    countReset: () => {},
    debug: () => {},
    dir: () => {},
    dirxml: () => {},
    error: () => {},
    group: () => {},
    groupCollapsed: () => {},
    groupEnd: () => {},
    info: () => {},
    log: () => {},
    memory: console.memory,
    profile: () => {},
    profileEnd: () => {},
    reactStack: () => {},
    reactStackEnd: () => {},
    table: () => {},
    time: () => {},
    timeEnd: () => {},
    timeLog: () => {},
    timeStamp: () => {},
    trace: () => {},
    warn: () => {}
  };
`;

const unpackCommandProject = (commandProject: CommandProject): [ProjectState, Selection] => [
  {
    sampleRate: commandProject.sampleRate,
    tracks: commandProject.tracks.map((track) => ({
      audioBuffers: [track.audioBuffer],
      height: Math.min(track.height, expandedTrackHeight),
      title: track.title
    }))
  },
  [
    [
      Math.min(commandProject.selectionStart || 0, commandProject.selectionEnd || 0) || 0,
      Math.max(commandProject.selectionStart || 0, commandProject.selectionEnd || 0) || 0
    ],
    commandProject.tracks.map((t, i) => t.selected ? i : null).filter((i) => i !== null)
  ]
] as [ProjectState, Selection];

ctx.addEventListener('message', (event) => {
  if (event.data.event && event.data.event.startsWith('wavtool-command-')) {
    const projectState = fromSendable(event.data.projectState);
    const selection = event.data.selection;
    const settings = event.data.settings;
    const isTest = event.data.isTest;
    try {
      const execute = new Function(`
        const wavtool = arguments[0];
        const project = arguments[1];

        ${isTest ? consoleOverride : ''}

        ${event.data.code}

        return [project, wavtool.__settings];
      `);

      const wavtool = initStandardLibrary(projectState.sampleRate, settings);
      const project = new CommandProject(projectState, selection, wavtool);

      const [newProject, discoveredSettings] = execute(wavtool, project);
      const [newProjectState, newSelection] = unpackCommandProject(newProject);

      ctx.postMessage(
        {
          event: `${event.data.event}-result`,
          projectState: toSendable(newProjectState),
          selection: newSelection,
          discoveredSettings
        }
      );
    } catch (e) {
      if (!isTest) {
        throw e;
      }
    }
  } else if (event.data === 'ping') {
    ctx.postMessage('pong')
  }
});

export default {} as typeof Worker & (new () => Worker);

