/** @jsx jsx */
import { jsx } from '@emotion/core';
import styled from '@emotion/styled';
import { gray100, gray300, gray800 } from '../../styles/colors_v2';
import { MajorButton } from '../../styles/elements';
import { useCallback, useContext, useState, useMemo, Fragment, useEffect } from 'react';
import { ProjectContext } from '../../hooks/useProject';
import { ScreenConfigurationContext } from '../../hooks/useScreenConfiguration';
import { openToolbarWidth, closedToolbarWidth } from '../../styles/dimensions';
import HeaderTab from '../HeaderTab';
import { ReactComponent as SaveIcon } from '../../icons/Save.svg';
import { ReactComponent as SettingsIcon } from '../../icons/Settings.svg';
import HeaderTabTitle from '../HeaderTabTitle';
import api from '../../api';
import { CommandEditorContext, hasChanges, SaveableCommand } from '../../hooks/useCommandEditor';
import { useCommandSettings, CommandSettingsContext } from '../../hooks/useCommandSettings';
import CommandSettings from './CommandSettings';
import CommandSaveForm from './CommandSaveForm';
import { StoredCommand, CommandCategory, AuthState } from '../../types';
import { AuthContext } from '../../hooks/useAuth';
import LoginButton from '../LoginButton';
import Editor from "@monaco-editor/react";
import { WalkthroughContext } from '../../hooks/useWalkthrough';
import useStorageBackedState from '../../hooks/useStorageBackedState';


const TabList = styled.div`
  display: flex;
  justify-content: flex-start;
`;

const EditorWrapper = styled.div<{hide: boolean}>`
  height: 100%;
  min-height: 0;
  width: 100%;
  min-width: 0;
  grid-column: 1;
  grid-row: 3;
  display: grid;
  position: relative;
  padding-top: 2px;
  &:after {
    content: '';
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background-image: linear-gradient(rgba(18,18,18,0.8), rgba(18,18,18,0))
  }
  ${({ hide }) => hide && `
    .monaco-editor {
      opacity: 0;
    }
  `}
`;

const SavePrompt = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: ${gray800};
  padding: 12px;
  text-align: center;
  height: 100%;
  p {
    margin: 20px 0;
    padding: 0;
    &+p {
      margin-top: 0;
    }
  }
`;

const SettingsSection = styled.div`
  border-left: 4px solid ${gray300};
  grid-row-start: 2;
  grid-row-end: 4;
  position: relative;
  overflow: hidden;
`;

const CopyButton = styled(MajorButton)`
  padding: 10px 20px;
`;

const STATE_PREFIX = `feb-18-2021-command-editor`;

export default ({ focusedCommand }: { focusedCommand: SaveableCommand }) => {
  const { state, interactions } = useContext(ProjectContext);
  const screenConfiguration = useContext(ScreenConfigurationContext);
  const commandEditor = useContext(CommandEditorContext);
  const [message, setMessage] = useState<string | null>(null);

  const commandSettings = useCommandSettings(focusedCommand.code, state);

  const onExecute = useCallback(
    () => {
      interactions.timelineContent.executeCommand(
        focusedCommand,
        commandSettings.settingValues,
        commandSettings.setCommandSettings
      );
    },
    [interactions.timelineContent, commandSettings.settingValues, commandSettings.setCommandSettings, focusedCommand]
  );

  const onCodeChange = useCallback(
    (newCode) => {
      commandEditor.updateFocusedCommand({ ...focusedCommand, code: newCode });
    },
    [commandEditor, focusedCommand]
  );

  const auth = useContext(AuthContext);

  const mustCopyToSave = useMemo(() => {
    return focusedCommand.author_id !== undefined && focusedCommand.author_id !== auth.user?.id;
  }, [focusedCommand, auth]);

  const mustLoginToSave = useMemo(() => {
    return auth.state !== AuthState.LoggedIn;
  }, [auth]);

  const onMakeCopy = useCallback(
    () => {
      commandEditor.openCommand({
        ...focusedCommand,
        author_id: undefined,
        author_name: undefined,
        id: `${focusedCommand.id}-copy`,
        name: `Copy of ${focusedCommand.name}`,
        lastSavedState: undefined
      });
    },
    [commandEditor, focusedCommand]
  );

  const saveAndUpdateFocusedCommand = useCallback(
    async (command: StoredCommand ) => {
      const id = (typeof command.id === 'string') ? undefined : command.id;
      const result = await api.save({ ...command, id });
      if (result.status === 'success') {
        commandEditor.updateFocusedCommand({
          ...command,
          id: result.id,
          lastSavedState: command
        });
        setMessage('Saved successfully!');
        console.log(`Link to code:\n${window.location.protocol}//${window.location.host}?code=${result.id}`);
        console.log(`Link to code with demo audio:\n${window.location.protocol}//${window.location.host}?code=${result.id}&audio=drums`);
        console.log(`Note: Demo audio will not load if the user has other audio loaded`)
        console.log(`Note: Other users will not be able to open or run your code until we verify it.`);
      } else {
        setMessage(`Error: ${result.message}`);
      }
    },
    [commandEditor]
  );

  const onSubmitSaveForm = useCallback(
    (name: string, description: string, category: CommandCategory) => {
      saveAndUpdateFocusedCommand({
        ...focusedCommand,
        name,
        description,
        category
      });
    },
    [focusedCommand, saveAndUpdateFocusedCommand]
  );

  const [showingSave, setShowingSave] = useStorageBackedState(false, `${STATE_PREFIX}-showing-save`);
  const [editorMounted, setEditorMounted] = useState(false);
  const editorWidth = window.innerWidth - (300 + (screenConfiguration.toolbarOpen ? openToolbarWidth : closedToolbarWidth))

  const isVisible = screenConfiguration.commandViewHeight > 5;
  const walkthrough = useContext(WalkthroughContext);

  useEffect(() => {
    if (isVisible) {
      walkthrough.seeCode();
    }
  }, [isVisible, walkthrough]);

  return (
    <CommandSettingsContext.Provider value={commandSettings}>
      <EditorWrapper hide={!editorMounted}>
        <Editor
          width={editorWidth}
          onChange={onCodeChange}
          defaultLanguage="typescript"
          value={focusedCommand.code}
          onMount={(editor, monaco) => {
            monaco.editor.defineTheme('wavtool', {
              base: 'vs-dark',
              inherit: true,
              rules: [{ background: gray100.replace('#', '') }],
              colors: { 'editor.background': gray100 }
            });
            monaco.editor.setTheme('wavtool');
            // eslint-disable-next-line import/no-webpack-loader-syntax
            monaco.languages.typescript.typescriptDefaults.addExtraLib(require('!!raw-loader!../../audio/commands/CommandGlobals.d.ts').default, '');
            setEditorMounted(true);
            editor.updateOptions({ wordWrap: 'on', wrappingIndent: 'indent', automaticLayout: true });
          }}
          theme="vs-dark"
        />
      </EditorWrapper>
      <SettingsSection>
        <TabList>
          <HeaderTab active={!showingSave} onClick={() => setShowingSave(false)} style={{ paddingLeft: 8 }}>
            <SettingsIcon />
            <HeaderTabTitle value="Run Code" />
          </HeaderTab>
          <HeaderTab active={showingSave} onClick={() => setShowingSave(true)}>
            <SaveIcon />
            <HeaderTabTitle value="Save Code" />
          </HeaderTab>
        </TabList>
        {!showingSave && (
          <CommandSettings onExecute={onExecute} />
        )}
        {showingSave && (
          <Fragment>
            {!mustLoginToSave && !mustCopyToSave && (
              <CommandSaveForm
                message={message}
                hasChanges={hasChanges(focusedCommand)}
                onSubmit={onSubmitSaveForm}
                focusedCommand={focusedCommand}
              />
            )}
            {mustLoginToSave && (
              <SavePrompt>
                <h3>Log in to continue</h3>
                <p>You must be logged in to save</p>
                <LoginButton />
              </SavePrompt>
            )}
            {!mustLoginToSave && mustCopyToSave && (
              <SavePrompt>
                <h3>Copy to continue</h3>
                <p>To save your changes, create your own copy of "<em>{focusedCommand.name}</em>"</p>
                <CopyButton onClick={onMakeCopy}>Make a Copy</CopyButton>
              </SavePrompt>
            )}
          </Fragment>
        )}
      </SettingsSection>
    </CommandSettingsContext.Provider>
  )
}
